前言:為什麼選擇 DOM4J
- **易用性**:API 設計貼合 Java 集合框架,鏈式調用、泛型支持
- **性能**:SAX 事件驅動構建樹,內存效率優於 DOM
- **功能完整**:原生支持 XPath、XSLT、Namespaces、XML Schema 驗證
- **生態地位**:Hibernate、Spring 早期版本核心 XML 解析器
官網:dom4j.org
一、核心類速覽
| 類/接口 | 包 | 核心職責 |
Document | org.dom4j | 文檔根節點,工廠方法創建元素 |
Element | org.dom4j | 元素節點,屬性/子元素/文本操作 |
DocumentHelper | org.dom4j | 靜態工廠:createDocument()、parseText() |
SAXReader | org.dom4j.io | SAX 解析器,文件/流/URL → Document |
XMLWriter | org.dom4j.io | Document → 流/文件/輸出流,支持格式化 |
OutputFormat | org.dom4j.io | 輸出格式控制:縮排、編碼、換行、聲明 |
二、完整示例:創建、寫入、讀取、輸出
import org.dom4j.*;
import org.dom4j.io.*;
public class DOMCreator {
public static void main(String[] args) throws Exception {
// 1. 創建文檔結構
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement("Table");
Element row = root.addElement("Row");
Element item = row.addElement("Item");
item.addText("data");
// 2. 格式化寫入文件
OutputFormat format = OutputFormat.createPrettyPrint(); // 縮排、換行
XMLWriter writer = new XMLWriter(new FileWriter("dom4j.xml"), format);
writer.write(doc);
writer.close();
// 3. 讀取並輸出到控制台
SAXReader reader = new SAXReader();
Document loaded = reader.read("dom4j.xml");
XMLWriter console = new XMLWriter(System.out, format);
console.write(loaded);
console.close();
}
}
三、進階操作模式
1. XPath 查詢 (核心優勢)
// 選擇所有 Item 元素
List items = doc.selectNodes("//Item");
// 選擇第一個 Row 的 Item 文本
String text = doc.selectSingleNode("//Row[1]/Item").getText();
// 命名空間查詢
Map ns = Map.of("ns", "https://example.com");
Element e = doc.selectSingleNode("//ns:Element", ns);
2. 屬性操作
Element elem = root.addElement("User").addAttribute("id", "123");
String id = elem.attributeValue("id"); // 直接獲取值
elem.addAttribute("status", "active");
3. 節點遍歷與修改
// 迭代器遍歷 (支持刪除)
for (Iterator it = root.elementIterator("Row"); it.hasNext(); ) {
Element row = it.next();
if ("delete".equals(row.attributeValue("action"))) it.remove();
}
// 訪問者模式遍歷 (只讀)
new VisitorSupport() {
@Override public void visit(Element node) { /* 處理 */ }
}.visit(doc);
4. XSLT 轉換
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource("style.xsl"));
transformer.transform(new DocumentSource(doc), new StreamResult(new File("output.html")));
四、常量定義最佳實踐
public interface Constants {
String DATA_TABLE = "Table";
String DATA_ROW = "Row";
String DATA_ITEM = "Item";
// 統一管理元素/屬性名稱,避免字符串分散
}
五、性能與內存優化建議
- 大文件流式處理:實現
ElementHandler 配合 SAXReader.setElementHandler(),單元素處理後釋放內存
- 復用 DocumentFactory:自定義工廠創建輕量級節點實現
- 避免頻繁創建 XMLWriter:批量寫入時復用實例
- 關閉實體解析:
reader.setFeature("https://apache.org/xml/features/disallow-doctype-decl", true) 防 XXE
六、常見問題排查
| 問題 | 原因 | 解決 |
| 編碼亂碼 | OutputFormat 未設置編碼 / 文件實際編碼不匹配 | format.setEncoding("UTF-8");讀取時指定 reader.setEncoding() |
| XPath 查無結果 | 命名空間未註冊 / 路徑大小寫錯誤 | 檢查 doc.getRootElement().getNamespace();使用 selectNodes(xpath, nsMap) |
| 內存溢出 | 超大文檔全量構建樹 | 改用 ElementHandler 流式處理或 StAX |
| JAR 衝突 | 類路徑存在多版本 dom4j/jaxen | Maven dependency:tree 排查,統一版本 |
七、現代替代方案對比
| 方案 | 優勢 | 劣勢 | 適用場景 |
| DOM4J | XPath 強、API 友好、成熟穩定 | 全量樹內存、維護模式 | 中小型 XML、配置文件、報表導出 |
| JDOM | 純 Java、API 直觀 | 性能較弱、功能較少 | 教學、簡單配置 |
| StAX (JSR-173) | 流式、雙向游標、低內存、標準 API | 無 XPath、編程模式較底層 | 大文件、高性能解析/生成 |
| JAXB | 對象綁定、類型安全、註解驅動 | 需 Schema/註解、啟動慢 | 數據交換、配置對象圖 |
| XStream | 無註解 POJO 序列化、極簡 API | 不支持 Schema、安全性歷史問題 | 內部數據序列化、測試數據 |
八、總結
DOM4J 以 **XPath 原生支持、鏈式 API、格式化輸出** 三大優勢,成為 Java XML 處理的經典選擇。掌握 DocumentHelper 創建、SAXReader 解析、XMLWriter 輸出、selectNodes 查詢四大核心流程,配合 ElementHandler 流式優化,可應對 90% XML 處理場景。新項目建議優先考慮 **JAXB (數據綁定)** 或 **StAX (高性能流式)**,DOM4J 適合存量維護與 XPath 密集型業務。