来学习XML文件的解析,不管是度还是写xml文件,第一件事情就是先解析。例如,我们看到很多配置文件是xml,里面有key和value,对应的程序代码就需要去解析xml文件,拿到用户修改的值去更改软件的设置。早期的网站,数据传输很多都是采用xml文件,例如用户请求一个接口,接口返回来就是xml内容,在发相应内容给前端之前,代码是需要解析xml并往里面写入请求之后的数据。
XML解析思想
XML常见的解析方式有DOM和xpath两种,这篇我们主要来看DOM解析。DOM即Document Object Model,文档对象模型),将文档加载进内存,形成一颗dom树(document对象),将文档的各个组成部分封装为一些对象。
DOM解析的优缺点
优点:有了dom树,可以在内存中对dom树进行增删改查操作。
缺点:dom树非常占内存,解析速度慢。例如有1kb的xml文档,转成dom树在内存中可能占用1M内存。
DOM解析可以解析出下面五大结点
Document
Element
Text
Attribute
Comment
上面五个对象,下面代码我们会练习到。
SAX解析
特点:逐行读取,基于事件驱动
优点:不占内存,速度快
缺点:只能读取,不能写
XML常用的解析器
*JAXP:sun公司提供的,支持dom和sax,不好用,几乎没人使用
*JDOM:半路夭折
*DOM4J:dom for java,开源的产品,借鉴了前面两者的优点,避免了缺点,支持dom
使用步骤:
1.导入dom4j.jar文件
2.创建解析器 SAXReader reader = new SAXReader()
3.解析xml获得document对象 Document document = reader.read(url)
DOM4J 下载
这里我下载dom4j-2.1.1,jdk8以上版本可以使用这个版本的DOM4J,下载下来是一个jar,我们把这个添加到项目的build path中去。准备一个student.xml文件,放到项目的根目录下(和src同级)。
<?xml version="1.0" encoding="UTF-8" ?>
<students>
<student>
<name>ZS</name>
<age>18</age>
<gender>male</gender>
</student>
<student>
<name>LS</name>
<age>19</age>
<gender>female</gender>
</student>
</students>
有了这个xml测试文件,现在我们就可以对照https://dom4j.github.io/ 上面的例子去实现代码。
解析XML文件,得到document对象
package com.anthony.parse;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
public class DOM4JTest {
public static void main(String[] args) throws DocumentException {
Document doc = parse("student.xml");
System.out.println(doc.toString());
}
public static Document parse(String xmlPath) throws DocumentException {
SAXReader reader = new SAXReader();
Document doc = reader.read(xmlPath);
return doc;
}
}
得到的document对象打印出现是一个内存地址。接下来,我们先拿到根元素,然后遍历标签和属性。
遍历标签和属
思路就是先得到根节点,通过根节点可以遍历根节点的第一层子节点,当然如果子节点下还有嵌套子节点,我们程序就写for嵌套就行。这里我们准备的student.xml就两层嵌套标签。我下面的代码是拿到students根节点,然后拿到student这个子节点,然后继续迭代拿到name age gender三个标签,最后通过ele.getStringValue()方法来打印标签的文本内容,也就是我们的value。我们这个xml文件没有写标签的属性和属性值。
package com.anthony.parse;
import java.util.Iterator;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class DOM4JTest {
public static void main(String[] args) throws DocumentException {
// get document object
Document doc = parse("student.xml");
getElementInfo(doc);
}
public static Document parse(String xmlPath) throws DocumentException {
SAXReader reader = new SAXReader();
Document doc = reader.read(xmlPath);
return doc;
}
public static void getElementInfo(Document doc) {
//get root element
Element root = doc.getRootElement();
// iterate through child elements of root
for(Iterator<Element> it = root.elementIterator(); it.hasNext();) {
Element element = it.next();
System.out.println(element.getStringValue());
}
}
}
运行结果
ZS
18
male
LS
19
female
递归元素
其实上面迭代器方式是很消耗内存,DOM4J网页上说,如果解析一个比较大的xml文档,不建议使用迭代器的方式,而是选择递归的方法。下面来看看递归如何拿到每个元素的文本内容。
package com.anthony.parse;
import java.util.Iterator;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
public class DOM4JTest {
public static void main(String[] args) throws DocumentException {
// get document object
Document doc = parse("student.xml");
// get root element
Element root = doc.getRootElement();
treeWalk(root);
}
public static Document parse(String xmlPath) throws DocumentException {
SAXReader reader = new SAXReader();
Document doc = reader.read(xmlPath);
return doc;
}
//递归方式,如果节点是元素标签,那么继续递归,如果不是,打印出标签的文本信息
public static void treeWalk(Element element) {
for (int i = 0, size = element.nodeCount(); i < size; i++) {
Node node = element.node(i);
if (node instanceof Element) {
treeWalk((Element) node);
} else {
System.out.println(node.getStringValue());
}
}
}
}
运行结果
ZS
18
male
LS
19
female
运行结果很多空行。
如果我们确定xml文档中根节点下,只需要解析出特定名称的元素的信息,那么上面getElementinfo方法可以修改成这样。
package com.anthony.parse;
import java.util.Iterator;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
public class DOM4JTest {
public static void main(String[] args) throws DocumentException {
// get document object
Document doc = parse("student.xml");
getElementInfoWithName(doc);
}
public static Document parse(String xmlPath) throws DocumentException {
SAXReader reader = new SAXReader();
Document doc = reader.read(xmlPath);
return doc;
}
public static void getElementInfo(Document doc) {
//get root element
Element root = doc.getRootElement();
// iterate through child elements of root
for(Iterator<Element> it = root.elementIterator(); it.hasNext();) {
Element element = it.next();
System.out.println(element.getStringValue());
}
}
// 指定迭代特定名称的子节点的信息,这里只student这个标签的名称
public static void getElementInfoWithName(Document doc) {
//get root element
Element root = doc.getRootElement();
// iterate through child elements of root
for(Iterator<Element> it = root.elementIterator("student"); it.hasNext();) {
Element element = it.next();
System.out.println(element.getStringValue());
}
}
}
运行结果是一样的。
上面都是读取文件和解析些xml内容,下面介绍DOM4J来写内容到xml文件。
我们写的这个student-new.xml,默认生成在根目录下,内容和上面student.xml一样,看看我的代码是如何实现的。
package com.anthony.parse;
import java.io.FileWriter;
import java.io.IOException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
public class DOM4JWriteTest {
public static void main(String[] args) throws IOException {
Document doc = createDocument();
FileWriter out = new FileWriter("student-new.xml");
doc.write(out);
out.close();
}
public static Document createDocument() {
Document doc = DocumentHelper.createDocument();
//add root element
Element root = doc.addElement("students");
//add student1
Element student1 = root.addElement("student");
student1.addElement("age")
.addText("18");
student1.addElement("name")
.addText("ZhangSan");
student1.addElement("agender")
.addText("male");
//add student2
Element student2 = root.addElement("student");
student2.addElement("age")
.addText("19");
student2.addElement("name")
.addText("LiSi");
student2.addElement("agender")
.addText("female");
return doc;
}
}
运行结果,刷新项目,根目录下就出现student-new.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<students><student><age>18</age><name>ZhangSan</name><agender>male</agender></student><student><age>19</age><name>LiSi</name><agender>female</agender></student></students>
打开student-new.xml 内容是这样,内容是对,只不过是没有换行,不美观,这个没关系,你可以手动一个标签一个标签去换行试试,效果就是说明按照你想要的格式写入了内容。写入xml的思路就是,先创建一个document对象,然后定义根标签,然后根标签下定义一个标签,名称你自己写一个,然后一层添加标签,添加属性或者添加Text。