初學者常遇困惑:DOM 樹在內存中修改後,原 XML 文件未同步更新。JAXP 本身不提供持久化 API,需開發者自行選擇序列化方案。本文對比四種主流方法,分析優劣與適用場景。
XmlDocument.write()(舊項目維護)DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document doc = factory.newDocumentBuilder().parse("user.xml");
// ... 修改 doc ...
((org.apache.crimson.tree.XmlDocument) doc).write(
new FileOutputStream("user.xml")); // 默認 UTF-8
// 或指定編碼
((XmlDocument) doc).write(new OutputStreamWriter(new FileOutputStream("user.xml"), "GB2312"));
Transformer(推薦標準做法)// 1. 準備源與結果
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File("output.xml"));
// 2. 獲取 Transformer
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
// 3. 【關鍵】設置輸出屬性
Properties props = t.getOutputProperties();
props.setProperty(OutputKeys.ENCODING, "GB2312"); // 解決中文亂碼
props.setProperty(OutputKeys.INDENT, "yes"); // 縮排美化
props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
t.setOutputProperties(props);
// 4. 執行轉換
t.transform(source, result);
OutputKeys 常用屬性速查| 屬性常量 | 說明 | 典型值 |
|---|---|---|
| METHOD | 輸出格式 | xml / html / text |
| VERSION | XML/HTML 版本 | 1.0 / 4.0 |
| ENCODING | 字符編碼 | UTF-8 / GB2312 |
| INDENT | 是否縮排 | yes / no |
| OMIT_XML_DECLARATION | 省略 XML 聲明 | yes / no |
| MEDIA_TYPE | MIME 類型 | text/xml |
// 前同方案三:建立 Transformer、設置屬性、transform(source, domResult)
// 額外步驟:
DOMResult domResult = new DOMResult();
t.transform(new DOMSource(doc), domResult);
Serializer serializer = SerializerFactory.getSerializer(
OutputProperties.getDefaultMethodProperties("xml"));
Properties sp = serializer.getOutputFormat();
sp.setProperty("encoding", "GB2312");
serializer.setOutputFormat(sp);
serializer.setOutputStream(new FileOutputStream("output.xml"));
serializer.asDOMSerializer().serialize(domResult.getNode());
| 維度 | 手工寫入 | Crimson write() | Transformer (推薦) | Xalan Serializer |
|---|---|---|---|---|
| 標準化 | 無 | 專有 | JAXP 標準 | 專有 |
| 編碼控制 | 自行處理 | 支援 | 完整支援 | 完整支援 |
| 格式控制 | 極難 | 無 | 豐富 (OutputKeys) | 豐富 |
| 解析器綁定 | 無 | Crimson | 無 (Pluggable) | Xalan/Xerces |
| 大文件性能 | 差 | 中 | 中 (受限於 DOM) | 較好 |
| 維護成本 | 高 | 高 (棄用風險) | 低 | 中 |
XMLStreamWriter 流式輸出,避免 DOM 佔用海量堆內存。Transformer 配置、異常處理、資源關閉封裝為 XmlUtils.writeXml(Document, OutputStream, Encoding),業務代碼一行調用。XMLUnit 或 Canonical XML 比對期望輸出。XMLOutputter / XMLWriter API 更友好,內部同樣委託 Transformer 或自帶序列化器。「修改 DOM 後如何落盤」不是 JAXP 缺失,而是設計使然:解析與序列化分離。掌握 Transformer + OutputKeys 標準組合,即可輕鬆應對 95% 場景;極致性能才引入 Xalan Serializer 或流式寫入。拒絕手工拼接、拒絕綁定廠商專有類,是專業 Java XML 開發者的基本素養。