DOM4J (dom4j.org) 是 Java 平台上最受歡迎的開源 XML 解析庫,融合了 Java Collection Framework,完整支援 DOM、SAX、JAXP 與 XPath。本文系統整理其核心介面體系,並提供五大實戰場景完整代碼:建立、修改、遍歷、ElementHandler 處理大文件、XSLT 轉換。
Element (元素)、Document (文檔)。CDATA、Text、Comment。
dom4j-1.6.1.jarjaxen-1.1.1.jar (XPath 支援必須)Document document = DocumentHelper.createDocument();
// ProcessingInstruction
Map<String, String> piMap = new HashMap<>();
piMap.put("type", "text/xsl"); piMap.put("href", "students.xsl");
document.addProcessingInstruction("xml-stylesheet", piMap);
// 根元素
Element students = document.addElement("students");
students.addComment("An Student Catalog");
// 子元素鏈式調用
Element stu = students.addElement("student").addAttribute("sn", "01");
stu.addElement("name").setText("sam");
stu.addElement("age").setText("18");
// ... 更多元素
return document;
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>...";
Document document = DocumentHelper.parseText(xml); // 需 try-catch DocumentException
OutputFormat format = OutputFormat.createPrettyPrint(); // 或 createCompactFormat()
format.setEncoding("UTF-8"); // 指定編碼
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"), format);
writer.write(document); writer.close();
需 jaxen.jar。示範修改第一個 student 的 sn 屬性與 name 文字:
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("students-gen.xml"));
// 修改屬性
for (Attribute attr : (List<Attribute>) doc.selectNodes("//students/student/@sn")) {
if ("01".equals(attr.getValue())) attr.setValue("001");
}
// 修改元素文字
for (Element stu : (List<Element>) doc.selectNodes("//students/student")) {
Element name = stu.element("name");
if ("sam".equals(name.getText())) name.setText("jeff");
}
new XMLWriter(new FileWriter("students-modified.xml")).write(doc);
Element root = doc.getRootElement();
for (Iterator<Element> it = root.elementIterator(); it.hasNext(); ) {
Element e = it.next();
System.out.println(e.getName());
for (Iterator<Attribute> ait = e.attributeIterator(); ait.hasNext(); ) {
Attribute a = ait.next(); System.out.println(a.getName() + ":" + a.getValue());
}
for (Iterator<Element> sit = e.elementIterator(); sit.hasNext(); ) {
Element se = sit.next(); System.out.println(se.getName() + ":" + se.getText());
}
}
doc.accept(new VisitorSupport() {
public void visit(Attribute node) { System.out.println("attr: " + node.getName() + "=" + node.getValue()); }
public void visit(ProcessingInstruction node) { System.out.println("PI: " + node.getTarget() + " " + node.getText()); }
public void visit(Element node) {
if (node.isTextOnly()) System.out.println("elem: " + node.getName() + "=" + node.getText());
else System.out.println("--------" + node.getName() + "--------");
}
});
注意:accept() 會自動遞歸整棵樹,切勿在 visit 中再手動遞歸,否則重複處理。
針對特定路徑註冊處理器,解析時回調,適合 GB 級文件:
SAXReader reader = new SAXReader();
reader.addHandler("/students/student", new ElementHandler() {
public void onStart(ElementPath path) {
Element stu = path.getCurrent();
System.out.println("Found student: " + stu.attributeValue("sn"));
path.addHandler("name", new ElementHandler() { // 巢狀處理子元素
public void onEnd(ElementPath path) {
Element name = path.getCurrent();
System.out.println(name.getName() + " : " + name.getText());
}
});
}
public void onEnd(ElementPath path) { path.removeHandler("name"); }
});
reader.read(new File("students.xml")); // 不返回 Document,邊讀邊處理
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource("style.xsl"));
DocumentSource source = new DocumentSource(doc);
DocumentResult result = new DocumentResult();
transformer.transform(source, result);
Document transformedDoc = result.getDocument(); // 取得轉換後的 DOM4J Document
DOM4J 以直觀 API、XPath 原生支援、Visitor/Handler 進階模式,成為 Java XML 處理首選。掌握上述五大場景,可覆蓋 95% 實務需求:小文件用 DOM 模式隨心所欲,大文件用 Handler 流式處理,轉換用 JAXP 橋接標準。