目录
- 为什么选择 dom4j?
- 准备工作:添加依赖
- 核心 API 介绍
- 实战案例:解析 XML 文件
- 读取 XML 文件
- 遍历文档结构
- 获取节点信息(名称、文本、属性)
- 处理命名空间
- 实战案例:创建/生成 XML 文件
- XPath 支持
- 总结与最佳实践
为什么选择 dom4j?
在 Java 中,除了 dom4j,还有其他几种常见的 XML 解析技术:

- DOM (Document Object Model): 由 W3C 标准,它将整个 XML 文档加载到内存中,形成一个树形结构,优点是操作方便,可以随意增删改查;缺点是极其消耗内存,不适合处理大文件。
- SAX (Simple API for XML): 事件驱动模型,它不会加载整个文档,而是按顺序读取,遇到元素开始、结束等事件时触发相应的回调方法,优点是内存占用小,速度快;缺点是只能读不能写,且操作复杂,只能顺序访问。
- JAXP (Java API for XML Processing): 是 Java 自带的 API,是
DOM和SAX的封装,提供了标准的工厂方法来创建解析器。
dom4j 的优势:
- 性能卓越:
dom4j使用了多种优化技术,其性能远超标准的 DOM 和 SAX 解析器。 - 功能强大: 除了基本的 DOM 操作,它还支持 XPath、XSLT、Schema 等高级 XML 标准。
- 易于使用: API 设计非常直观,学习曲线平缓。
- 灵活性好: 可以与多种解析器(如 JDK 自带的、Aelfred 等)配合使用。
对于大多数 Java 项目,dom4j 是一个“全能型选手”,既能高效解析,又能方便地生成 XML,是处理 XML 的最佳选择。
准备工作:添加依赖
你需要将 dom4j 的库添加到你的项目中,如果你使用 Maven,只需在 pom.xml 中添加以下依赖:
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version> <!-- 建议使用较新版本 -->
</dependency>
注意:dom4j 依赖于另一个 XML 解析器(如 Aelfred2 或 JAXP)来实际解析 XML,如果你使用的是 JDK 1.4 或更高版本,JAXP 解析器通常是可用的,无需额外依赖。

核心 API 介绍
dom4j 的核心类构成了一个树形结构来表示 XML 文档。
| 类/接口 | 描述 |
|---|---|
Document |
代表整个 XML 文档,它是树的根节点。 |
Element |
代表 XML 中的一个元素(标签),如 <book>、<author>。 |
Attribute |
代表元素的属性,如 id="001"。 |
Node |
所有节点(Document, Element, Attribute 等)的基接口。 |
Branch |
可以包含子节点的节点(Document, Element)。 |
DocumentHelper |
一个工厂类,用于创建 Document, Element 等对象。 |
SAXReader |
用于将 XML 文档(从文件、流或 URL)解析为 Document 对象的核心类。 |
实战案例:解析 XML 文件
假设我们有以下一个 books.xml 文件:
books.xml
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="001">
<name>Learning XML</name>
<author> Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
<book id="002">
<name>Java in Action</name>
<author> Craig Walls</author>
<year>2012</year>
<price>49.99</price>
</book>
</bookstore>
步骤 1:读取 XML 文件并获取 Document 对象
我们需要使用 SAXReader 来读取文件并构建 Document 树。

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import java.io.File;
public class XmlParser {
public static void main(String[] args) {
// 1. 创建 SAXReader 对象
SAXReader reader = new SAXReader();
try {
// 2. 读取 XML 文件,获取 Document 对象
// 注意:文件路径要正确
Document document = reader.read(new File("src/main/resources/books.xml"));
// 3. 获取 XML 文档的根元素
Element rootElement = document.getRootElement();
// 4. 开始解析...
System.out.println("根元素是: " + rootElement.getName());
parseBook(rootElement);
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
步骤 2 & 3:遍历文档结构并获取节点信息
dom4j 提供了多种遍历方式,最常用的是 elementIterator()。
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.Iterator;
public class XmlParser {
public static void main(String[] args) {
// ... (前面的代码)
try {
Document document = reader.read(new File("src/main/resources/books.xml"));
Element rootElement = document.getRootElement();
System.out.println("根元素是: " + rootElement.getName());
// 遍历根元素下的所有 <book> 元素
Iterator<Element> bookIterator = rootElement.elementIterator("book");
while (bookIterator.hasNext()) {
Element bookElement = bookIterator.next();
System.out.println("\n--- 开始解析一本书 ---");
// 获取元素的属性
String bookId = bookElement.attributeValue("id");
System.out.println("书籍 ID: " + bookId);
// 遍历 <book> 元素下的所有子元素
Iterator<Element> childIterator = bookElement.elementIterator();
while (childIterator.hasNext()) {
Element childElement = childIterator.next();
System.out.println(
childElement.getName() + ": " + childElement.getTextTrim()
);
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
代码解释:
rootElement.elementIterator("book"): 获取名为 "book" 的所有子元素的迭代器,如果参数为空,则获取所有子元素。bookElement.attributeValue("id"): 获取名为 "id" 的属性的值。childElement.getName(): 获取元素的名称(如 "name", "author")。childElement.getTextTrim(): 获取元素内的文本内容,并去除前后空白。推荐使用getTextTrim()而不是getText(),因为getText()会保留换行和缩进,可能包含很多无用的空白字符。
输出结果:
根元素是: bookstore
--- 开始解析一本书 ---
书籍 ID: 001
name: Learning XML
author: Erik T. Ray
year: 2003
price: 39.95
--- 开始解析一本书 ---
书籍 ID: 002
name: Java in Action
author: Craig Walls
year: 2012
price: 49.99
步骤 4:处理命名空间
XML 文件使用了命名空间,解析方式会稍有不同。
<ns:bookstore xmlns:ns="http://www.example.com/books">
<ns:book ns:id="001">
<ns:name>Learning XML</ns:name>
</ns:book>
</ns:bookstore>
处理命名空间需要使用 QName (Qualified Name)。
// ... (SAXReader 和 Document 获取部分)
Element rootElement = document.getRootElement();
// 定义命名空间
Namespace ns = Namespace.get("ns", "http://www.example.com/books");
// 使用 QName 来查找带命名空间的元素
Element bookElement = rootElement.element(QName.get("book", ns));
if (bookElement != null) {
// 同样使用 QName 获取属性
String bookId = bookElement.attributeValue(QName.get("id", ns));
System.out.println("书籍 ID: " + bookId);
Element nameElement = bookElement.element(QName.get("name", ns));
System.out.println("书名: " + nameElement.getTextTrim());
}
实战案例:创建/生成 XML 文件
使用 dom4j 创建 XML 文件同样非常简单,主要是构建 Document 树,然后使用 XMLWriter 将其写入文件。
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import java.io.FileWriter;
import java.io.IOException;
public class XmlCreator {
public static void main(String[] args) {
// 1. 创建一个 Document 对象
Document document = DocumentHelper.createDocument();
// 2. 添加根元素
Element rootElement = document.addElement("bookstore");
// 3. 添加子元素
Element book1 = rootElement.addElement("book")
.addAttribute("id", "003");
book1.addElement("name").addText("Effective Java");
book1.addElement("author").addText("Joshua Bloch");
book1.addElement("year").addText("2008");
book1.addElement("price").addText("59.99");
Element book2 = rootElement.addElement("book")
.addAttribute("id", "004");
book2.addElement("name").addText("Design Patterns");
book2.addElement("author").addText("Gang of Four");
book2.addElement("year").addText("1994");
book2.addElement("price").addText("49.50");
// 4. 设置输出格式(美化输出)
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
// 5. 创建 XMLWriter 并写入文件
try (FileWriter fileWriter = new FileWriter("src/main/resources/new_books.xml")) {
XMLWriter writer = new XMLWriter(fileWriter, format);
writer.write(document);
writer.close();
System.out.println("XML 文件生成成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
new_books.xml 生成的结果:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="003">
<name>Effective Java</name>
<author>Joshua Bloch</author>
<year>2008</year>
<price>59.99</price>
</book>
<book id="004">
<name>Design Patterns</name>
<author>Gang of Four</author>
<year>1994</year>
<price>49.50</price>
</book>
</bookstore>
XPath 支持
dom4j 对 XPath 提供了强大的支持,可以让你像在数据库中查询数据一样快速定位 XML 节点。
// ... (假设 document 和 reader 已经准备好)
// 1. 导入 XPath 相关类
import org.dom4j.XPath;
// 2. 获取所有 <book> 节点
List<Node> books = document.selectNodes("//book");
System.out.println("共有 " + books.size() + " 本书。");
// 3. 获取第一本书的 <name> 节点
Node firstBookName = document.selectSingleNode("//book[1]/name");
System.out.println("第一本书的名字是: " + firstBookName.getText());
// 4. 获取 id 为 "002" 的书的 <author> 节点
Node authorOfBook002 = document.selectSingleNode("//book[@id='002']/author");
System.out.println("ID为002的书的作者是: " + authorOfBook002.getText());
// 5. 使用 XPath 表达式获取所有价格大于40的书
List<Node> expensiveBooks = document.selectNodes("//book[price > 40]");
System.out.println("\n价格大于40的书有:");
for (Node book : expensiveBooks) {
Element bookEl = (Element) book;
System.out.println(" - " + bookEl.elementText("name") + " (价格: " + bookEl.elementText("price") + ")");
}
总结与最佳实践
| 场景 | 推荐技术 | 原因 |
|---|---|---|
| 解析大型 XML 文件 | SAX 或 StAX | 内存占用小,速度快。dom4j 底层也可以配置为使用 SAX 模式。 |
| 解析小型或中型 XML 文件 | dom4j (DOM) |
API 简洁,操作灵活,功能全面。 |
| 需要频繁查询 XML | dom4j + XPath |
XPath 是查询 XML 的利器,比手动遍历高效得多。 |
| 需要生成 XML | dom4j |
API 直观,易于构建树形结构,并能控制输出格式。 |
| Java 内置项目,不想引入新库 | JAXP (DOM/SAX) | 标准库,无需额外依赖,但 API 相对繁琐。 |
dom4j 最佳实践:
- 异常处理: XML 解析过程可能会抛出
DocumentException,务必进行捕获和处理。 - 资源管理: 使用
try-with-resources语句来管理FileWriter等资源,确保它们被正确关闭。 - 使用
getTextTrim(): 在获取元素文本内容时,优先使用getTextTrim()以避免不必要的空白字符。 - 利用 XPath: 对于复杂的查询,不要害怕使用 XPath,它能极大简化你的代码。
- 性能考虑: 对于非常大的文件,如果内存成为瓶颈,可以考虑使用基于事件的解析器(如 SAX),或者使用
dom4j的SAXReader进行流式处理。
