在 Java 處理 XML 的四大主流方案(DOM、SAX、StAX、JDOM)中,JDOM 以「純 Java 設計、API 直觀、記憶體效率優於 DOM」著稱。JDOM 2.x 全面支援 Java 8+、Namespace、XPath、XSLT、Schema 驗證,是伺服器端配置檔解析、資料交換的優秀選擇。本文以實務範例示範完整讀寫流程。
org.jdom
jdom2
2.0.6.1
jaxen
jaxen
1.2.0
implementation("org.jdom:jdom2:2.0.6.1")
implementation("jaxen:jaxen:1.2.0")
檔案:books.xml
Effective Java
Joshua Bloch
2018
45.99
9780134685991
Clean Architecture
Robert C. Martin
2017
38.50
9780134494166
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.filter.Filters;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import java.io.File;
import java.util.List;
public class JdomReadDemo {
public static void main(String[] args) throws Exception {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("books.xml"));
Element root = doc.getRootElement();
// 取得所有 book 元素
List books = root.getChildren("book");
for (Element book : books) {
String id = book.getAttributeValue("id");
String category = book.getAttributeValue("category");
String title = book.getChild("title").getText();
String author = book.getChildText("author");
double price = Double.parseDouble(book.getChildText("price"));
System.out.printf("ID: %s | 類別: %s | 書名: %s | 作者: %s | 價格: %.2f%n",
id, category, title, author, price);
}
}
}
public class JdomXPathDemo {
public static void main(String[] args) throws Exception {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("books.xml"));
XPathFactory xpf = XPathFactory.instance();
// 查詢所有 programming 類別的書名
XPathExpression expr = xpf.compile(
"//book[@category='programming']/title", Filters.element());
List titles = expr.evaluate(doc);
System.out.println("Programming 類別書名:");
titles.forEach(e -> System.out.println(" - " + e.getText()));
// 查詢價格大於 40 的書籍(需自訂邏輯或 XSLT)
// JDOM 本身不支援 XPath 2.0 數值比較,建議用 Java Stream 過濾
List expensiveBooks = root.getChildren("book").stream()
.filter(b -> Double.parseDouble(b.getChildText("price")) > 40)
.toList();
System.out.println("\n價格 > 40 的書籍:");
expensiveBooks.forEach(b -> System.out.println(" - " + b.getChildText("title")));
}
}
import org.jdom2.Namespace;
public class JdomNamespaceDemo {
public static void main(String[] args) throws Exception {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("books.xml"));
Element root = doc.getRootElement();
// 定義命名空間
Namespace bkNs = Namespace.getNamespace("bk", "https://example.com/bookstore");
// 使用命名空間查詢子元素
for (Element book : root.getChildren("book")) {
Element title = book.getChild("title", bkNs); // 關鍵:指定 Namespace
String lang = title.getAttributeValue("lang", Namespace.NO_NAMESPACE);
System.out.println("書名: " + title.getText() + " (語言: " + lang + ")");
}
}
}
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import java.io.FileWriter;
public class JdomWriteDemo {
public static void main(String[] args) throws Exception {
// 定義命名空間
Namespace bkNs = Namespace.getNamespace("bk", "https://example.com/bookstore");
// 建立根元素
Element root = new Element("bookstore", bkNs);
root.addNamespaceDeclaration(bkNs); // 宣告 xmlns:bk
Document doc = new Document(root);
// 新增第一本書
Element book1 = new Element("book");
book1.setAttribute("id", "bk003");
book1.setAttribute("category", "microservices");
Element title1 = new Element("title", bkNs);
title1.setAttribute("lang", "en");
title1.setText("Building Microservices");
book1.addContent(title1);
book1.addContent(new Element("author").setText("Sam Newman"));
book1.addContent(new Element("year").setText("2021"));
Element price1 = new Element("price");
price1.setAttribute("currency", "USD");
price1.setText("42.00");
book1.addContent(price1);
Element isbn1 = new Element("isbn");
isbn1.setAttribute("type", "ISBN-13");
isbn1.setText("9781492034025");
book1.addContent(isbn1);
root.addContent(book1);
// 輸出格式化 XML
Format format = Format.getPrettyFormat()
.setEncoding("UTF-8")
.setIndent(" ") // 4 空格縮排
.setLineSeparator("\n");
XMLOutputter outputter = new XMLOutputter(format);
try (FileWriter writer = new FileWriter("books_new.xml")) {
outputter.output(doc, writer);
}
System.out.println("XML 檔案寫入完成:books_new.xml");
}
}
public class JdomModifyDemo {
public static void main(String[] args) throws Exception {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("books.xml"));
Element root = doc.getRootElement();
// 找到特定書籍並更新價格
for (Element book : root.getChildren("book")) {
if ("bk001".equals(book.getAttributeValue("id"))) {
Element price = book.getChild("price");
double oldPrice = Double.parseDouble(price.getText());
double newPrice = oldPrice * 0.9; // 9 折
price.setText(String.format("%.2f", newPrice));
price.setAttribute("currency", "USD");
System.out.println("更新價格: " + oldPrice + " -> " + newPrice);
break;
}
}
// 寫回原檔(建議先備份)
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
try (FileWriter writer = new FileWriter("books.xml")) {
outputter.output(doc, writer);
}
}
}
import org.jdom2.input.sax.XMLReaders;
import org.xml.sax.SAXException;
public class JdomValidationDemo {
public static void main(String[] args) {
try {
// 建立支援 Schema 驗證的 Builder
SAXBuilder builder = new SAXBuilder(XMLReaders.XSDVALIDATING);
builder.setProperty("https://java.sun.com/xml/jaxp/properties/schemaLanguage",
"https://www.w3.org/2001/XMLSchema");
builder.setProperty("https://java.sun.com/xml/jaxp/properties/schemaSource",
new File("bookstore.xsd"));
Document doc = builder.build(new File("books.xml"));
System.out.println("✓ XML 通過 Schema 驗證");
} catch (SAXException e) {
System.err.println("✗ Schema 驗證失敗: " + e.getMessage());
} catch (Exception e) {
System.err.println("解析錯誤: " + e.getMessage());
}
}
}
| 解析器 | 記憶體模型 | 適用場景 | 速度 |
|---|---|---|---|
| DOM / JDOM | 樹狀結構全載入記憶體 | 中小型 XML、需隨機存取、修改 | 中等 |
| SAX | 事件驅動、不建樹 | 大型 XML、單向讀取、記憶體受限 | 快 |
| StAX | 拉取式、游標控制 | 大型 XML、需部分跳過、雙向控制 | 快 |
| JDOM + SAXBuilder | 建樹但可配合 Filter | 大多數企業應用最佳平衡點 | 中等 |
SAXBuilder 搭配 ElementFilter 只建立需要的子樹javax.xml.stream) 手動處理流式讀寫Format.getCompactFormat() 減小體積JDOM 2.x 提供了符合 Java 慣用語的 XML 操作 API,在可讀性、功能完整度與效能間取得良好平衡。掌握 SAXBuilder 解析、XPath 查詢、Namespace 處理、XMLOutputter 序列化四大核心操作,即可應對絕大多數企業級 XML 整合場景。對於超大型 XML 或極致效能需求,可考慮 StAX 或 SAX 作為補充方案。