配置文件、數據交換、報表生成等場景需程序化操作 XML。DOM 樹模型適合中小文檔 (≤50MB),XPath 提供強大查詢能力。
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
public class XMLUtil {
/** 解析文件獲取 Document */
public static Document parse(String filePath) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // 關鍵:支持命名空間
factory.setIgnoringElementContentWhitespace(true); // 忽略格式化空白
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new File(filePath));
}
/** XPath 查詢單節點 */
public static Node selectSingleNode(String xpathExpr, Object source) {
try {
XPath xpath = XPathFactory.newInstance().newXPath();
return (Node) xpath.evaluate(xpathExpr, source, XPathConstants.NODE);
} catch (XPathExpressionException e) {
throw new RuntimeException("XPath 查詢失敗: " + xpathExpr, e);
}
}
/** XPath 查詢節點列表 */
public static NodeList selectNodes(String xpathExpr, Object source) {
try {
XPath xpath = XPathFactory.newInstance().newXPath();
return (NodeList) xpath.evaluate(xpathExpr, source, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
throw new RuntimeException("XPath 查詢失敗: " + xpathExpr, e);
}
}
/** 節點輸出為字符串 (控制台/調試) */
public static String nodeToString(Node node) {
try {
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "yes");
tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
StringWriter sw = new StringWriter();
tf.transform(new DOMSource(node), new StreamResult(sw));
return sw.toString();
} catch (TransformerException e) {
throw new RuntimeException("節點序列化失敗", e);
}
}
/** Document 保存到文件 */
public static void save(Document doc, String filePath) {
try {
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "yes");
tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
tf.transform(new DOMSource(doc), new StreamResult(new File(filePath)));
} catch (TransformerException e) {
throw new RuntimeException("XML 保存失敗", e);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="B01">
<name>Harry Potter</name>
<price>10</price>
<memo>Magic</memo>
</book>
<book id="B02">
<name>Three Kingdoms</name>
<price>10</price>
<memo>Classic</memo>
</book>
<book id="B03">
<name>Water Margin</name>
<price>6</price>
<memo>Classic</memo>
</book>
</books>
Document doc = XMLUtil.parse("books.xml");
Element root = doc.getDocumentElement();
Node book = XMLUtil.selectSingleNode("/books/book[name='Harry Potter']", root);
String price = XMLUtil.selectSingleNode("price/text()", book).getNodeValue();
System.out.println("價格: " + price); // 10
Element newBook = doc.createElement("book");
newBook.setAttribute("id", "B04");
appendChild(doc, newBook, "name", "New Book");
appendChild(doc, newBook, "price", "20");
appendChild(doc, newBook, "memo", "Brand new");
root.appendChild(newBook);
Node priceNode = XMLUtil.selectSingleNode("/books/book[name='Harry Potter']/price", root);
priceNode.setTextContent("15");
Element bookElem = (Element) XMLUtil.selectSingleNode("/books/book[name='Harry Potter']", root);
bookElem.setAttribute("edition", "2nd");
// 刪除 id=B02
Node toDel = XMLUtil.selectSingleNode("/books/book[@id='B02']", root);
toDel.getParentNode().removeChild(toDel);
// 批量刪除 price < 10
NodeList cheapBooks = XMLUtil.selectNodes("/books/book[price < 10]", root);
for (int i = 0; i < cheapBooks.getLength(); i++) {
cheapBooks.item(i).getParentNode().removeChild(cheapBooks.item(i));
}
XMLUtil.save(doc, "books_updated.xml");
// XML: ...
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
return "ns".equals(prefix) ? "https://example.com" : XMLConstants.NULL_NS_URI;
}
public String getPrefix(String uri) { return "ns"; }
public Iterator getPrefixes(String uri) { return null; }
});
Node item = (Node) xpath.evaluate("/ns:root/ns:item", doc, XPathConstants.NODE);
DOM + XPath 是 Java 處理 XML 的標準組合:**命名空間感知、XPath 查詢、DOM 修改、Transformer 輸出** 四步走。大文件 (>100MB) 請改用 StAX (流式) 或 SAX (事件驅動) 避免 OOM。