dom4j 是 Java 平台上優秀的開源 XML 解析庫,靈活性高、API 直觀、性能優異,支持 XPath、XSLT、Schema 驗證等高級特性。本文系統梳理 dom4j 核心用法,幫助開發者快速上手 XML 處理。
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
</dependency>
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import java.io.File;
public Document parseXml(String filePath) throws DocumentException {
SAXReader reader = new SAXReader();
// 支持 File、InputStream、URL、Reader 等多種數據源
Document document = reader.read(new File(filePath));
// 讀取時自動按 XML 聲明編碼轉換,亂碼問題通常源於編碼聲明與實際不符
return document;
}
import org.dom4j.Element;
Element root = document.getRootElement();
// 根元素是整個 XML 文檔的入口,所有節點遍歷從此開始
for (Iterator<Element> it = root.elementIterator(); it.hasNext(); ) {
Element element = it.next();
// 處理元素...
}
// 僅遍歷名為 "book" 的子元素
for (Iterator<Element> it = root.elementIterator("book"); it.hasNext(); ) {
Element book = it.next();
// 處理 book 元素...
}
for (Iterator<Attribute> it = root.attributeIterator(); it.hasNext(); ) {
Attribute attr = it.next();
System.out.println(attr.getName() + " = " + attr.getValue());
}
import java.util.List;
// 獲取所有直接子元素
List<Element> children = root.elements();
// 獲取指定名稱的子元素列表
List<Element> books = root.elements("book");
// 核心屬性獲取方法
String elementName = element.getName(); // 元素名稱
String elementText = element.getText(); // 文本內容(含子元素文本)
String elementTextTrim = element.getTextTrim(); // 去除首尾空白
Attribute attr = element.attribute("id"); // 獲取指定屬性對象
String attrValue = element.attributeValue("id"); // 直接獲取屬性值(安全,不拋 NPE)
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<book id="bk101" category="programming">
<title>Java 核心技術</title>
<author>Cay Horstmann</author>
<price currency="CNY">128.00</price>
<publish_date>2023-03-15</publish_date>
</book>
<book id="bk102" category="database">
<title>MySQL 實戰 45 講</title>
<author>林曉斌</author>
<price currency="CNY">89.90</price>
<publish_date>2022-11-20</publish_date>
</book>
</catalog>
public void parseBooks(String xmlPath) throws DocumentException {
Document doc = parseXml(xmlPath);
Element root = doc.getRootElement();
List<Element> books = root.elements("book");
for (Element book : books) {
String id = book.attributeValue("id");
String category = book.attributeValue("category");
String title = book.elementText("title");
String author = book.elementText("author");
String price = book.elementText("price");
String currency = book.element("price").attributeValue("currency");
String pubDate = book.elementText("publish_date");
System.out.printf("【%s】%s / %s / %s %s (%s)%n", id, title, author, price, currency, pubDate);
}
}
// 選擇所有價格 > 100 的書籍
List<Node> expensiveBooks = document.selectNodes("//book[price > 100]");
// 獲取第一本書的作者
String firstAuthor = document.selectSingleNode("//book[1]/author").getText();
<?xml version="1.0" encoding="UTF-8"?>reader.read(inputStream, "UTF-8")OutputFormat format = OutputFormat.createPrettyPrint(); format.setEncoding("UTF-8");對於超大 XML(>100MB),DOM 模型會導致 OOM。dom4j 提供 SAXReader 配合 ElementHandler 實現邊讀邊處理:
SAXReader reader = new SAXReader();
reader.addElementHandler("/catalog/book", new ElementHandler() {
@Override
public void onStart(ElementPath path) {}
@Override
public void onEnd(ElementPath path) {
Element book = path.getCurrent();
// 處理單個 book 元素
processBook(book);
// 關鍵:處理完立即釋放內存
path.getCurrent().detach();
}
});
reader.read(new File("huge.xml"));
// 註冊命名空間前綴
Map<String, String> nsMap = new HashMap<>();
nsMap.put("ns", "https://example.com/namespace");
XPath xpath = document.createXPath("//ns:book");
xpath.setNamespaceURIs(nsMap);
| 問題 | 原因 | 解決方案 |
|---|---|---|
| getText() 返回空串 | 元素包含子元素,文本在子節點中 | 使用 elementText() 或遍歷 textNodes() |
| 屬性值獲取拋 NPE | attribute() 返回 null 時調用 getValue() | 改用 attributeValue() 安全獲取 |
| 中文亂碼 | 文件實際編碼與聲明不一致 | 統一使用 UTF-8,或指定編碼讀取 |
| 大文件 OOM | DOM 全量加載進內存 | 使用 ElementHandler 流式處理 |
dom4j 以靈活的 API 和豐富的功能成為 Java XML 處理的首選。掌握基本遍歷、XPath 查詢、流式處理、命名空間等核心技能,能應對 95% 的 XML 業務場景。建議在新項目中考慮更現代的 Jackson XML 或 JAXB 實現對象綁定,進一步提升開發效率。