使用 Dom4j 操作 XML

引言:XML(可扩展标记语言)在软件开发工程中取得了广泛的应用。在 Java 语言中操作 XML 有许多方法,最常用的方法就是使用 JDom、Dom4j 等第三方组件。本文将简单介绍使用 Dom4j 操作 XML 的基本方法。

本文采用的 Dom4j 版本为 1.6.1,下载地址见文章结尾。 废话不多说,先来看一下本文使用的 XML 文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<class id="1">
<student>
<num>0001</num>
<name>张三</name>
<age>19</age>
</student>

<student>
<num>0002</num>
<name>李四</name>
<age>21</age>
<hobby>
<name>足球</name>
<name>篮球</name>
</hobby>
</student>

<teacher>
<name>王老师</name>
<age>40</age>
<course>Java</course>
</teacher>
</class>

在这个 XML 文件中,可以看到根节点为 class,它有 student 和 teacher 子节点,而 student 子节点中又包含 num、name、age、hobby 等孙子辈节点,teacher 子节点中包含 name、age、course 等孙子辈节点。 下面就使用 dom4j 来操作这个 xml 文件。

解析 XML

当使用 dom4j 操作 xml 时,你想做的第一件事可能就是解析一个 Xml 文档,这个操作在 dom4j 中十分容易,使用下面的代码即可以轻松的解析 xml 文件并返回一个 Document 对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package cn.javacodes.dom4j;

import java.io.File;

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

public class TestDom4j {

public static void main(String[] args) throws Exception {
// 获取SAX阅读器
SAXReader reader = new SAXReader();
// 获取Document对象
Document doc = reader.read(new File("d:/DemoXML.xml"));
// 获取根节点
Element root = doc.getRootElement();
// 输出测试
System.out.println("根节点:" + root.getName() + ",id="
\+ root.attributeValue("id"));
}

}

输出结果:

根节点:class,id=1

使用迭代器 Iterator

一个 Element 对象可以通过几个方法来返回一个标准的 Java 迭代器: (1)迭代所有子元素

1
2
3
4
5
// 迭代root元素的所有子元素
for (Iterator i = root.elementIterator(); i.hasNext(); ) {
Element element = (Element) i.next();
System.out.println(element.getName());
}

输出结果:

student student teacher

(2)通过元素名称迭代

1
2
3
4
5
// 通过元素名称“student”迭代子元素
for ( Iterator i = root.elementIterator( "student" ); i.hasNext(); ) {
Element foo = (Element) i.next();
System.out.println(foo.getName());
}

输出结果:

student student

(3)迭代所有属性

1
2
3
4
5
// 迭代root元素的所有属性
for ( Iterator i = root.attributeIterator(); i.hasNext(); ) {
Attribute attribute = (Attribute) i.next();
System.out.println(attribute.getName() + ":" + attribute.getValue());
}

输出结果:

id:1

获取元素值

通常我们都需要获取 xml 元素标签内部的文本,也就是元素值,下面一个简单的例子递归显示所有的元素值:

1
2
3
4
5
6
7
8
9
10
public  static void showAllElementText(Element e){
for (Iterator i = e.elementIterator(); i.hasNext(); ) {
Element element = (Element) i.next();
if (!element.elements().isEmpty()) {
showAllElementText(element);
} else {
System.out.println(element.getName()+"="+element.getTextTrim());
}
}
}

输出结果

num=0001 name = 张三 age=19 num=0002 name = 李四 age=21 name = 足球 name = 篮球 name = 王老师 age=40 course=Java

使用 XPath 表达式

在 Dom4j 中使用 XPath 表达式可以更加轻松的操作 XML 文档,使用 XPath 表达式可以使用仅一行代码来进行复杂的操作,在 Dom4j 中使用 XPath 的几个简单示例代码如下: (1)查询单个节点(默认查找第一个):

1
2
3
4
5
6
7
8
// 获取SAX阅读器
SAXReader reader = new SAXReader();
// 获取Document对象
Document doc = reader.read(new File("d:/DemoXML.xml"));
// 获取student元素的name节点
Node node = doc.selectSingleNode("//student/name");
// 输出测试
System.out.println(node.getName() + "=" + node.getText());

(2)查询多个节点

1
2
3
4
5
6
7
// 获取所有student元素的name节点
List<Node> list = doc.selectNodes("//student");
// 输出测试
for (Node node : list) {
    System.out.println(node.getName()
\+ ":" \+ node.valueOf("name"));
}

以上为两种经常使用的方法,另外如果你想在一个 XHTML 文档中查找到所有的超文本链接,可以使用下面这个窍门轻松实现:

1
2
3
4
5
6
7
public void findLinks(Document document) throws DocumentException {
List list = document.selectNodes( "//a/@href" );
for (Iterator iter = list.iterator(); iter.hasNext(); ) {
Attribute attribute = (Attribute) iter.next();
String url = attribute.getValue();
}
}

如果你需要任何有关学习 XPah 表达式语言的帮助,你可以访问 Zvon tutorial 进行学习,这里可以通过各种各样的例子帮助你学习。

快速循环

如果你需要操作一个十分庞大的 XML 文档,那么你应该使用快速循环的方法以避免在每次循环都创建 Iterator 对象,下面是一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void treeWalk(Document document) {
treeWalk( document.getRootElement() );
}

public 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 {
// 这里写你想要做的操作
}
}
}

创建 XML Document 对象

在使用 Dom4j 时经常需要创建一个新的 document,下面是一个简单的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class Foo {

public Document createDocument() {
Document document = DocumentHelper.createDocument();
Element root = document.addElement( "root" );

Element author1 = root.addElement( "author" )
.addAttribute( "name", "James" )
.addAttribute( "location", "UK" )
.addText( "James Strachan" );

Element author2 = root.addElement( "author" )
.addAttribute( "name", "Bob" )
.addAttribute( "location", "US" )
.addText( "Bob McWhirter" );

return document;
}
}

写入 XML 文件

使用 Dom4j 将 Document 对象写入到 XML 文件十分简单,你只需要 1 行代码即可解决:

1
document.write( new FileWriter( "foo.xml" ));

如果你想修改输出的格式,例如更易读的排版或者压缩(紧凑)的排版,再或者你想通过 Writer 或 OutputStream 进行输出,那么你可以使用 XMLWriter 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

public class Foo {

public void write(Document document) throws IOException {

// 写入到一个文件
XMLWriter writer = new XMLWriter(
new FileWriter( "output.xml" )
);
writer.write( document );
writer.close();


// 更加美观的排版
OutputFormat format = OutputFormat.createPrettyPrint();
writer = new XMLWriter( System.out, format );
writer.write( document );

// 更加紧凑的排版
format = OutputFormat.createCompactFormat();
writer = new XMLWriter( System.out, format );
writer.write( document );
}
}

Document 对象与 XML 代码互转

如果你想通过一个 Document 对象或其他任何节点对象(例如 Attribute 或 Element),你可以通过 asXML () 方法将它转换为 XML 文本字符串,例如:

1
2
Document document = ...;
String text = document.asXML();

如果你想从一个 XML 文本字符串转为一个 Document 对象,你可以使用 DocumentHelper.parseText () 方法进行解析:

1
2
String text = "<person> <name>James</name> </person>";
Document document = DocumentHelper.parseText(text);

XSLT

通过 Sum 公司提供的 JAXP API 在一个 Document 上应用 XSLT 十分简单。这里有一个使用 JAXP 创建一个 transformer 并应用到 Document 上的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;

import org.dom4j.Document;
import org.dom4j.io.DocumentResult;
import org.dom4j.io.DocumentSource;

public class Foo {

public Document styleDocument(
Document document,
String stylesheet
) throws Exception {

// 使用JAXP加载transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(
new StreamSource( stylesheet )
);

// 样式化document
DocumentSource source = new DocumentSource( document );
DocumentResult result = new DocumentResult();
transformer.transform( source, result );

// 返回转换后的document
Document transformedDoc = result.getDocument();
return transformedDoc;
}
}