Java 中處理 XML 常用 DOM、SAX、JDOM、dom4j。其中 dom4j 以 API 簡潔、效能優異、支援 XPath、廣泛應用於 Hibernate、Spring 等框架,是首選庫。本文示範如何快速構建 XML 文件並輸出。
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
</dependency>
<!-- XPath 支援需額外引入 -->
<dependency>
<groupId>org.jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
// 建立空文件
Document document = DocumentHelper.createDocument();
// 建立根元素並加入文件
Element root = document.addElement("return");
// 在根元素下新增子元素
Element returnValue = root.addElement("returnvalue");
Element returnInfo = root.addElement("returninfo");
// 方式一:建立後設定文本
returnValue.addText("false");
returnInfo.addText("get-session-fail");
// 方式二:鏈式呼叫,建立同時設定文本
root.addElement("id").addText("12345");
root.addElement("timestamp").addText(String.valueOf(System.currentTimeMillis()));
// 避免 null 值導致例外:加上空字串
String nullableValue = getNullableString();
root.addElement("optional").addText(nullableValue + "");
// 非字串類型轉換
int id = 1;
root.addElement("id").addText(id + ""); // 整數
root.addElement("price").addText(99.9 + ""); // 浮點數
root.addElement("active").addText(true + ""); // 布林值
// CDATA 區段(包含特殊字元)
Element content = root.addElement("content");
content.addCDATA("");
// 設定屬性
Element user = root.addElement("user");
user.addAttribute("id", "1001");
user.addAttribute("role", "admin");
user.addText("John Doe");
// 輸出為字串
String xmlString = document.asXML();
System.out.println(xmlString);
// 輸出為檔案(格式化)
try (FileWriter fw = new FileWriter("output.xml")) {
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(fw, format);
writer.write(document);
writer.flush();
}
// 輸出到 HTTP 響應(Servlet)
response.setContentType("text/xml; charset=UTF-8");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(response.getWriter(), format);
writer.write(document);
writer.flush();
public class OrderXmlGenerator {
public static void main(String[] args) throws Exception {
Document doc = DocumentHelper.createDocument();
Element order = doc.addElement("order");
order.addAttribute("version", "1.0");
order.addAttribute("orderNo", "ORD-20240115-001");
// 客戶資訊
Element customer = order.addElement("customer");
customer.addElement("id").addText("CUST-1001");
customer.addElement("name").addText("張三");
customer.addElement("email").addText("zhangsan@example.com");
customer.addElement("phone").addText("0912-345-678");
// 商品清單
Element items = order.addElement("items");
addItem(items, "ITEM-001", "筆記型電腦", 1, 35000);
addItem(items, "ITEM-002", "無線滑鼠", 2, 590);
addItem(items, "ITEM-003", "機械鍵盤", 1, 2800);
// 總計
Element total = order.addElement("total");
total.addElement("subtotal").addText("41780");
total.addElement("discount").addText("0");
total.addElement("shipping").addText("120");
total.addElement("grandTotal").addText("41900");
// 狀態與時間
order.addElement("status").addText("CONFIRMED");
order.addElement("createdAt").addText("2024-01-15T10:30:00+08:00");
// 輸出
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(System.out, format);
writer.write(doc);
writer.flush();
}
private static void addItem(Element parent, String id, String name, int qty, int price) {
Element item = parent.addElement("item");
item.addAttribute("id", id);
item.addElement("name").addText(name);
item.addElement("quantity").addText(String.valueOf(qty));
item.addElement("unitPrice").addText(String.valueOf(price));
item.addElement("subtotal").addText(String.valueOf(qty * price));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<order version="1.0" orderNo="ORD-20240115-001">
<customer>
<id>CUST-1001</id>
<name>張三</name>
<email>zhangsan@example.com</email>
<phone>0912-345-678</phone>
</customer>
<items>
<item id="ITEM-001">
<name>筆記型電腦</name>
<quantity>1</quantity>
<unitPrice>35000</unitPrice>
<subtotal>35000</subtotal>
</item>
<item id="ITEM-002">
<name>無線滑鼠</name>
<quantity>2</quantity>
<unitPrice>590</unitPrice>
<subtotal>1180</subtotal>
</item>
<item id="ITEM-003">
<name>機械鍵盤</name>
<quantity>1</quantity>
<unitPrice>2800</unitPrice>
<subtotal>2800</subtotal>
</item>
</items>
<total>
<subtotal>41780</subtotal>
<discount>0</discount>
<shipping>120</shipping>
<grandTotal>41900</grandTotal>
</total>
<status>CONFIRMED</status>
<createdAt>2024-01-15T10:30:00+08:00</createdAt>
</order>
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement("root", "https://example.com/ns");
root.addNamespace("ns", "https://example.com/ns");
root.addNamespace("xsi", "https://www.w3.org/2001/XMLSchema-instance");
root.addAttribute("schemaLocation", "https://example.com/ns schema.xsd",
doc.getNamespaceForPrefix("xsi"));
public void objectToXml(Object obj, Element parent) {
Class> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
try {
Object value = field.get(obj);
if (value != null) {
Element child = parent.addElement(field.getName());
if (isPrimitiveOrWrapper(field.getType()) || value instanceof String) {
child.addText(value.toString());
} else if (value instanceof Collection) {
for (Object item : (Collection>) value) {
Element itemEl = child.addElement("item");
objectToXml(item, itemEl);
}
} else {
objectToXml(value, child); // 遞迴處理巢狀物件
}
}
} catch (IllegalAccessException e) { /* 忽略 */ }
}
}
// dom4j 不直接支援 StAX 輸出,大檔案建議用標準 javax.xml.stream
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter writer = factory.createXMLStreamWriter(new FileOutputStream("large.xml"));
writer.writeStartDocument("UTF-8", "1.0");
writer.writeStartElement("root");
// 循環寫入大量資料...
writer.writeEndElement();
writer.writeEndDocument();
writer.close();
| 問題 | 原因 | 解決 |
|---|---|---|
| addText(null) 拋出 NPE | dom4j 不接受 null | 使用 value + "" 或 Objects.toString(value, "") |
| 中文輸出亂碼 | 編碼不一致 | 設定 format.setEncoding("UTF-8")、確保檔案/輸出流編碼一致 |
| 特殊字元 (< > &) 未轉義 | 直接加入文本 | 使用 addText() 自動轉義、或 addCDATA() 包含原始內容 |
| 記憶體溢出 | 巨大 XML 全載入記憶體 | 改用 StAX 串流寫入、或分批生成 |
| XPath 查詢失效 | 缺少 jaxen.jar | 加入 jaxen 依賴 |
dom4j 以直觀的鏈式 API 讓 Java 構建 XML 變得簡單高效。掌握 DocumentHelper、Element、OutputFormat、XMLWriter 核心類別,配合屬性、CDATA、命名空間等進階功能,即可應對各種 XML 生成需求。大型檔案場景下請改用 StAX 串流式寫入避免記憶體壓力。