DOM(Document Object Model)是語言無關的 XML 標準,API 完整、實現多、穩定性強,適合企業級產品。但 DOM 面向結構非對象,Java 使用時較繁瑣。本文分享實戰封裝經驗。
XMLTool 設計封裝高頻操作,統一異常處理(檢查異常 → 運行時異常),提升開發效率。
// 1. 創建空 Document
public static Document newXMLDocument()
// 2. 字符串解析為 Document
public static Document parseXMLDocument(String xmlString)
public static Document parseXMLDocument(InputStream input)
public static Document loadXMLDocumentFromFile(String fileName)
// 3. 節點轉字符串
public static String toString(Node node)
// 4. 導入節點到新 Document
public static Document newXMLDocument(Node node)
// 5. 追加 Document/節點
public static void appendXMLDocument(Document doc, Document appendedDoc)
public static void appendXMLDocument(Node node, Node appendedNode)
// 6. 獲取 Transformer(統一編碼 gb2312、縮進關閉)
public static Transformer newTransformer()
// 7. 標準錯誤 XML 輸出
public static String errXMLString(String errMsg)
public static String errXMLString(String errMsg, Class errClass)
public static String errXMLString(String title, String errMsg, Class errClass)
關鍵點:ParserConfigurationException 等環境異常轉為 RuntimeException,業務代碼無需 try-catch;解析錯誤(SAXException、IOException)保留為 IllegalArgumentException 暴露參數問題。
DOM 中 <element>text</element> 的文本是獨立 Text 子節點,每次遍歷極繁瑣。約定:只取第一個直接 Text 子節點。
public static String getNodeValue(Node node) {
Text text = getTextNode(node);
return text != null ? text.getNodeValue() : null;
}
private static Text getTextNode(Node node) {
if (node == null || !node.hasChildNodes()) return null;
NodeList list = node.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
if (list.item(i).getNodeType() == Node.TEXT_NODE)
return (Text) list.item(i);
}
return null;
}
避免層層遍歷,利用 getElementsByTagName 取第一個匹配元素:
public static Element getFirstElementByName(Element element, String tagName) {
return (Element) getFirstElement(element.getElementsByTagName(tagName));
}
private static Node getFirstElement(NodeList list) {
return (list != null && list.getLength() > 0) ? list.item(0) : null;
}
約定:業務 XML 標簽名唯一或取首個,簡化 90% 場景。
DOM 規範禁止直接跨 Document 移動節點,需 importNode:
public static void appendXMLDocument(Node target, Node source) {
if (source == null) return;
if (source instanceof Document) source = ((Document)source).getDocumentElement();
target.appendChild(target.getOwnerDocument().importNode(source, true));
}
getElementById:依賴 DTD/Schema 定義 ID 屬性,非普通屬性 id,實際難用,建議放棄。getElementsByTagNameNS:命名空間場景少用,暫不封裝。getDocumentElement,其他同 Document。薄封裝層(XMLTool)屏蔽 DOM 冗長 API、統一異常、編碼、錯誤格式,配合業務約定(首文本節點、首同名元素),可將 XML 處理代碼量減少 60%+,提升可讀性與健壯性。現代項目亦可考慮 dom4j、JDOM2 或 Jackson XML 等對象映射庫進一步提效。