通过Java解析xml文档

一、xml解析方式概叙

1、解析方法

XML解析方式分为两种:dom和sax

dom:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式。

sax: (Simple API for XML) 不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。

2、解析器

Crimson、Xerces 、Aelfred2

3、解析开发包

Jaxp、Jdom、dom4j

4、解析方法比较

1.dom方法

优点:使用dom解析xml文档,实现crud特别方便,操作速度也比较快。

 

缺点:使用dom解析xml文档,如果文件比较大,对内存消耗就特别大,极容易导致内存溢出,所以dom方式不适合操作大的xml文档。

 

2.sax方法

优点:解析速度快、对内存占用少,查找数据特别方便

 

缺点:只适合查找数据,不适合作增删改操作

 

二、使用jaxp解析

1、dom方法解析

1、方法介绍

     javax.xml.parsers 包中的DocumentBuilderFactory用于创建DOM模式的解析器对象 , DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。

2、解析对象

book.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<书架>
	<书 name="yyyyyyy">
		<售价>109</售价>
		<售价>39元</售价>
		<书名>Java就业培训教程</书名>
		<作者>张孝祥</作者>
		
		
	</书>
	<书>
		<书名>JavaScript网页开发</书名>
		<作者>张孝祥</作者>
		<售价>28.00元</售价>
	</书>

</书架>

3、运用详情

package jaxp;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Demo {

	/**
	 * 使用jaxp操作xml文档
	 * @param args
	 * @throws ParserConfigurationException 
	 * @throws IOException 
	 * @throws SAXException 
	 */
	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
		//1.获取工厂
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		
		
		//2.产生解析器
		DocumentBuilder builder = factory.newDocumentBuilder();
		
		//3.解析xml文档,得到代表文档的document
		Document document = builder.parse(new File("src/book.xml"));

		//遍历
		list(document);
		
	}
	//遍历,得到所有标签
	public static void list(Node node){
		
        //判断得到的结点是否为标签
		if(node.getNodeType()==Node.ELEMENT_NODE){
			System.out.println(node.getNodeName());
		}
		
        //进行遍历
		NodeList list = node.getChildNodes();
		for(int i=0;i<list.getLength();i++){
			Node child = list.item(i);
			list(child);
		}
	}
	
	//------------------------对结点进行操作
	//得到售价结点的值
	@Test
	public void read() throws Exception{
		
		//1.获取工厂
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File("src/book.xml"));
		
		//2.得到第一个售价节点
		NodeList list = document.getElementsByTagName("售价");
		Node price = list.item(0);
		
		//3.得到该结点的值
		String value = price.getTextContent();
		System.out.println(value);
	}
	
	//修改结点的值:<售价>39.00元</售价>改为109
	@Test
	public  void update() throws Exception{
		
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder  builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File("src/book.xml"));
		
		Node price = document.getElementsByTagName("售价").item(0);
		price.setTextContent("109");
		
		
		//把内存中的document写到xml文档
		TransformerFactory tf = TransformerFactory.newInstance();
		//得到转换器
		Transformer ts = tf.newTransformer();
		ts.transform(new DOMSource(document), new StreamResult(new File("src/book.xml")));
	}
	
	
	//向指定节点中增加孩子节点(售价节点)
	@Test
	public void add() throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder  builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File("src/book.xml"));
		
		//创建需要增加的节点
		Node price = document.createElement("售价");
		price.setTextContent("59元");
		
		//得到需要增加的节点的父亲
		Node parent = document.getElementsByTagName("书").item(0);
		
		//把需要增加的节点挂到父结点上
		parent.appendChild(price);
		
		
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer ts = tf.newTransformer();
		ts.transform(new DOMSource(document), new StreamResult(new File("src/book.xml")));

	}
	
	//向指定位置上插入售价节点
	@Test
	public void add2() throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder  builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File("src/book.xml"));
		
		//新建要插入的结点
		Node node = document.createElement("售价");
		node.setTextContent("39元");
		
		Node parent = document.getElementsByTagName("书").item(0);//获取要插入的父节点
		parent.insertBefore(node, document.getElementsByTagName("书名").item(0));//在该节点的前边插入
		
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer ts = tf.newTransformer();
		ts.transform(new DOMSource(document), new StreamResult(new File("src/book.xml")));
	}
	
	//删除xml文档的售价结点
	@Test
	public void delete() throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder  builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File("src/book.xml"));
		
		Node node = document.getElementsByTagName("售价").item(2);
		node.getParentNode().removeChild(node);
		
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer ts = tf.newTransformer();
		ts.transform(new DOMSource(document), new StreamResult(new File("src/book1.xml")));
	}
	
	//--------------------------该标签属性
	//操作xml文档属性
	@Test
	public void updateAttribute() throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder  builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File("src/book.xml"));
		
		
		//操作xml文档的元素时,一般都把元素当作node对象,但是程序员如果发现node不好使时,就应把node强转成相应类型
		Node node  = document.getElementsByTagName("书").item(0);
		Element book = null;
		if(node.getNodeType()==Node.ELEMENT_NODE){  //在作结点转换之前,最好先判断结点类型
			book  = (Element)node;
		}
		//修改
		book.setAttribute("name", "yyyyyyy");
		//增加
		book.setAttribute("password", "123");
		//删除
		book.removeAttribute("password");
		
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer ts = tf.newTransformer();
		ts.transform(new DOMSource(document), new StreamResult(new File("src/book.xml")));
	}

}

 

4、案例解析

资料

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<exam>
	<student idcard="111" examid="222">
		<name>张三</name>
		<location>沈阳</location>
		<grade>89</grade>
	</student>
	
	<student idcard="333" examid="444">
		<name>李四</name>
		<location>大连</location>
		<grade>97</grade>
	</student>
	
</exam>

要求

1.需求分析

2.详细设计

添加用户:

 

删除用户:

 

查询成绩:

 

3.程序实现

javaben:student.java

public class Student {

	 /* <student idcard="111" examid="222">
		<name>张三</name>
		<location>沈阳</location>
		<grade>89</grade>
	</student>
	*/
	private String idcard;
	private String examid;
	private String name;
	private String location;
	private double grade;

}

工具类:Utils.java

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class XmlUtils {
	/**
	 * 工具类中的方法一般都是静态方法
	 * @return
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */

	//得到document
	public static Document getDocument() throws ParserConfigurationException, SAXException, IOException{
		
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		return builder.parse(new File("src/exam.xml"));
	}
	
	//将结果写入到xml文件
	public static void write2Xml(Document document) throws TransformerException{
		
		TransformerFactory factory = TransformerFactory.newInstance();
		Transformer tf = factory.newTransformer();
		tf.transform(new DOMSource(document), new StreamResult(new File("src/exam.xml")));
		
	}
}

持久化操作:StudentsDao.java

import java.io.IOException;

import javax.management.RuntimeErrorException;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.shen.mode.Student;
import com.shen.utils.XmlUtils;

public class StudentsDao {

	/*
	 <student idcard="111" examid="222">
		<name>张三</name>
		<location>沈阳</location>
		<grade>89</grade>
	</student>

	 */
	public void add(Student student){
		try{
			Document document = XmlUtils.getDocument();
			//student_node  //ctrl+1  rename in file
			Element student_node = document.createElement("student");
			student_node.setAttribute("examid", student.getExamid());
			student_node.setAttribute("idcard", student.getIdcard());
			
			Element name = document.createElement("name");
			name.setTextContent(student.getName());
			
			Element location = document.createElement("location");
			location.setTextContent(student.getLocation());
			
			Element grade = document.createElement("grade");
			grade.setTextContent(student.getGrade()+"");
			
			student_node.appendChild(name);
			student_node.appendChild(location);
			student_node.appendChild(grade);
			
			//得到exam结点,并把student挂上去
			document.getElementsByTagName("exam").item(0).appendChild(student_node);
			
			XmlUtils.write2Xml(document);
		}catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public void delete(String name){
		try {
			Document document=XmlUtils.getDocument();
			NodeList list=document.getElementsByTagName("name");
			for(int i=0;i<list.getLength();i++)
			{
				Node node=list.item(i);
				
				if(node.getTextContent().equals(name)){
					node.getParentNode().getParentNode().removeChild(node.getParentNode());
					XmlUtils.write2Xml(document);
					return;
				}
			}
			throw new RuntimeException("对不起,你要删除的学生不存在");//异常也是一个返回值
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	
	public Student find(String examid){
		
		try{
		Document document=XmlUtils.getDocument();
		
		NodeList list=document.getElementsByTagName("student");
		for (int i = 0; i < list.getLength(); i++) {
			Element student=(Element)list.item(i);
			String s_examid=student.getAttribute(examid);
			if(s_examid.equals(examid))
			{
				//找到
				Student s=new Student();
				s.setExamid(student.getAttribute("examid"));
				s.setExamid(student.getAttribute("idcard"));
				
				s.setName(student.getElementsByTagName("name").item(0).getTextContent());
				s.setLocation(student.getElementsByTagName("location").item(0).getTextContent());
				s.setGrade(Double.parseDouble(student.getElementsByTagName("garde").item(0).getTextContent()));
			    return s;
			    		
			}
		}
		
		return null;
		}catch(Exception e){}
		return null;
	}
}

主方法:Main.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import com.shen.dao.StudentsDao;
import com.shen.mode.Student;

public class Main {

	public static void main(String[] args) throws IOException {

		System.out.println("添加学生 (a)  查找学生(b)  删除学生(c)");
		System.out.print("请输入操作类型:");

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String type = br.readLine();

		if (type.equalsIgnoreCase("a")) {
			// 添加学生

			try {
				System.out.print("请输入学生姓名:");
				String name = br.readLine();

				System.out.print("请输入学生准考证号:");
				String examid = br.readLine();

				System.out.print("请输入学生身份证号:");
				String idcard = br.readLine();

				System.out.print("请输入学生所在地:");
				String location = br.readLine();

				System.out.print("请输入学生成绩:");
				String grade = br.readLine();

				Student student = new Student();
				student.setExamid(examid);
				student.setGrade(Double.parseDouble(grade));
				student.setIdcard(idcard);
				student.setLocation(location);
				student.setName(name);

				StudentsDao dao = new StudentsDao();
				dao.add(student);
				System.out.println("恭喜,录入成功!!!");
			} catch (Exception e) {
				System.out.println("对不起,录入失败!!");
			}

		} else if (type.equalsIgnoreCase("b")) {
			// 查找学生
			System.out.println("请输入学生的准考证号:");
			String examid=br.readLine();
			
			StudentsDao dao=new StudentsDao();
			Student student=dao.find(examid);
			if(student==null){
				System.out.println("对不起,你要查找的学生不存在!!!");
			}else{
				System.out.println("你要查找的学生信息如下:");
				System.out.println("姓名:"+student.getName());
				System.out.println("身份证:"+student.getIdcard());
				System.out.println("准考证:"+student.getExamid());
				System.out.println("所在地:"+student.getLocation());
				System.out.println("成绩"+student.getGrade());
			}
		} else if (type.equalsIgnoreCase("c")) {
			// 删除学生
			try{
			System.out.println("请输入要删除学生的姓名:");
			String name=br.readLine();
			
			StudentsDao dao=new StudentsDao();
			dao.delete(name);
			System.out.println("删除成功");
			}catch(Exception e){System.out.println("删除失败");}
		} else {
			System.out.println("不支持此类操作!!!");
		}

	}
}

2、sax方法解析

1、方法介绍

     在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。

2、解析对象

book.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<书架>
	<书 name="yyyyyyy">
		<售价>109</售价>
		<售价>39元</售价>
		<书名>Java就业培训教程</书名>
		<作者>张孝祥</作者>
		
		
	</书>
	<书>
		<书名>JavaScript网页开发</书名>
		<作者>张孝祥</作者>
		<售价>28.00元</售价>
	</书>
</书架>

3、运用详情

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class Demo1 {

	/**
	 *sax方式解析book1.xml文件
	 * @throws SAXException 
	 * @throws ParserConfigurationException 
	 * @throws IOException 
	 */
	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
		

		//1.创建工厂
		SAXParserFactory factory = SAXParserFactory.newInstance();
		
		//2.用工厂创建解析器
		SAXParser sp = factory.newSAXParser();
		
		//3.利用解析器得到reader
		XMLReader reader = sp.getXMLReader();
		
		//4、在解析xml文档之前,设置好事件处理器
		reader.setContentHandler(new MyContentHandler2());
		
		//4.利用reader读取 xml文档
		reader.parse("src/book1.xml");
	}
}
//用于获取第一个售价节点的值:<售价>109</售价>
class MyContentHandler2 extends DefaultHandler{

	private boolean isOk = false;
	private int index = 1;
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		if(isOk==true && index==1){
			System.out.println(new String(ch,start,length));
		}
	}

	@Override
	public void startElement(String uri, String localName, String name,
			Attributes attributes) throws SAXException {
		if(name.equals("售价")){
			isOk = true;
		}
	}

	@Override
	public void endElement(String uri, String localName, String name)
			throws SAXException {
		if(name.equals("售价")){
			isOk = false;
			index++;
		}
	}
	
	
	
	
	
}

//得到xml文档内容的事件处理器
class MyContentHandler implements ContentHandler{
        //开始标签(Attributes表示属性)
	public void startElement(String uri, String localName, String name,
			Attributes atts) throws SAXException {
		
		System.out.println("当前解析到了:" + name + ",这个标签是开始标签");
		for(int i=0;i<atts.getLength();i++){
			String attname = atts.getQName(i);
			String attvalue = atts.getValue(i);
			
                        //打印出各个属性
			System.out.println(attname + "=" + attvalue);
		}
		
		
	}
	
	public void endElement(String uri, String localName, String name)
	throws SAXException {
		
		System.out.println("当前解析到了:" + name + ",这个标签是结束标签");
	
	}
	
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		
		System.out.println("当前解析到了内容:" + new String(ch,start,length));
	}

	public void endDocument() throws SAXException {
		// TODO Auto-generated method stub
		
	}



	public void endPrefixMapping(String prefix) throws SAXException {
		// TODO Auto-generated method stub
		
	}

	public void ignorableWhitespace(char[] ch, int start, int length)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}

	public void processingInstruction(String target, String data)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}

	public void setDocumentLocator(Locator locator) {
		// TODO Auto-generated method stub
		
	}

	public void skippedEntity(String name) throws SAXException {
		// TODO Auto-generated method stub
		
	}

	public void startDocument() throws SAXException {
		// TODO Auto-generated method stub
		
	}

	

	public void startPrefixMapping(String prefix, String uri)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}


	
}

三、使用dom4j解析

     注意:使用dom4j解析需要自己引入jar包,引入该包可能不够

1、解析对象

book.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<书架>
	<书 name="yyyyyyy">
		<售价>109</售价>
		<售价>39元</售价>
		<书名>Java就业培训教程</书名>
		<作者>张孝祥</作者>
		
		
	</书>
	<书>
		<书名>JavaScript网页开发</书名>
		<作者>张孝祥</作者>
		<售价>28.00元</售价>
	</书>
</书架>

2、实现代码

public class Main {

	//读取xml文档数据:<书名>Java就业培训教程</书名>
	@Test
	public void read() throws Exception{
		
		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/book.xml"));
		
		Element root = document.getRootElement();
		Element bookname = root.element("书").element("书名");
		System.out.println(bookname.getText());
	}
	
	//<书 name="yyyyyyy">
	@Test
	public void readAttr() throws Exception{
		
		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/book.xml"));
		
		Element root = document.getRootElement();
		String value = root.element("书").attributeValue("name");
		System.out.println(value);
	}
	
	//向xml文档中添加<售价>19元</售价>
	@Test
	public void add() throws Exception{
		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/book.xml"));
		
		Element price = DocumentHelper.createElement("售价");
		price.setText("19元");
		
		document.getRootElement().element("书").add(price);
		
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("UTF-8");
		
		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
		writer.write(document);  //utf-8
		writer.close();
	}
	
	//修改:<售价>109</售价>  为209
	@Test
	public void update() throws Exception{
		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/book1.xml"));
		
		Element price = (Element) document.getRootElement().element("书").elements("售价").get(1);
		price.setText("209元");
		
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("UTF-8");
		
		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
		writer.write(document);  //utf-8
		writer.close();
		
	}
	//删除:<售价>109</售价>
	@Test
	public void delete() throws Exception{
		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/book.xml"));
		
		Element price = (Element) document.getRootElement().element("书").elements("售价").get(0);
		price.getParent().remove(price);
		
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("UTF-8");
		
		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
		writer.write(document);  //utf-8
		writer.close();
	}

	
	//向指定位置增加售价结点
	@Test
	public void add2() throws Exception{
		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/book.xml"));
		
		Element price = DocumentHelper.createElement("售价");
		price.setText("19元");
		
		List list = document.getRootElement().element("书").elements();
		list.add(1, price);
		
		//格式化输出(保持原来的样式)
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("UTF-8");
		
		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
		writer.write(document);  //utf-8
		writer.close();
		
	}

}

3、使用xpath技术实现查找

1.代码示例

import java.io.File;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;

public class Mais {

	@Test
	public void findWithXpath() throws Exception{
		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/book.xml"));
		
		Element e = (Element) document.selectNodes("//书名").get(1);
		System.out.println(e.getText());
	}
}

 

2.运用举例

     通过匹配用户信息进行登陆

users.xml

<?xml version="1.0" encoding="UTF-8"?>
<users>
	
	
	<user username="aaa" password="123"/>
	
	<user username="bbb" password="123"/>
	
	<user username="ccc" password="123"/>

</users>

login.java

	@Test
	public void findUser() throws Exception{
		String username = "aaa";
		String password = "1233";
		
		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/users.xml"));
		//single单一的
		Element e = (Element) document.selectSingleNode("//user[@username='"+username+"' and @password='"+password+"']");
		if(e!=null){
			System.out.println("让用户登陆成功!!");
		}else{
			System.out.println("用户名和密码不正确!!");
		}
	
	}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盡盡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值