DOM (Document Object Model) 解析器會一次性將整個 XML 文檔加載到內存,構建一棵完整的文檔對象樹。優點是操作直觀、支持隨機訪問、增刪改查靈活;缺點是內存佔用大,不適合大文件(>50MB 易 OOM)。正如原文吐槽:「代碼丑到吐」,這正是 JDOM、Dom4j、XStream 等封裝庫誕生的原因。
| 接口/類 | 核心作用 |
|---|---|
| DocumentBuilderFactory | 解析器工廠,獲取 DocumentBuilder |
| DocumentBuilder | 執行解析,生成 Document 對象 |
| Document | 文檔樹根節點,代表整個 XML 文檔 |
| Element | 元素節點,可獲取屬性、子元素、文本內容 |
| NodeList | 節點列表,按文檔順序存儲 |
| NamedNodeMap | 屬性集合,非有序 |
假設 books.xml 結構如下:
<books>
<book id="1" category="tech">
<title>Effective Java</title>
<author>Joshua Bloch</author>
</book>
<book id="2" category="novel">
<title>Three Body</title>
<author>Liu Cixin</author>
</book>
</books>
public class DomParserDemo {
public static void main(String[] args) throws Exception {
// 1. 獲取工廠與解析器
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 建議開啟命名空間感知,生產環境必開
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
// 2. 解析文件 -> Document 對象(全量加載入內存)
Document doc = builder.parse(new File("books.xml"));
// 3. 獲取根元素
Element root = doc.getDocumentElement(); //
// 4. 獲取所有 book 元素
NodeList bookList = root.getElementsByTagName("book");
// 5. 遍歷提取數據
for (int i = 0; i < bookList.getLength(); i++) {
Element book = (Element) bookList.item(i);
// 5.1 獲取屬性
String id = book.getAttribute("id");
String category = book.getAttribute("category");
// 5.2 獲取子元素文本(繞彎路:Element -> NodeList -> Node -> getTextContent)
String title = book.getElementsByTagName("title").item(0).getTextContent();
String author = book.getElementsByTagName("author").item(0).getTextContent();
System.out.printf("ID: %s | 類別: %s | 書名: %s | 作者: %s%n",
id, category, title, author);
}
}
}
ID: 1 | 類別: tech | 書名: Effective Java | 作者: Joshua Bloch
ID: 2 | 類別: novel | 書名: Three Body | 作者: Liu Cixin
標準 DOM 需鏈式調用:getElementsByTagName -> item(0) -> getTextContent()。封裝工具方法:
private String getChildText(Element parent, String tagName) {
NodeList list = parent.getElementsByTagName(tagName);
return list.getLength() > 0 ? list.item(0).getTextContent() : "";
}
大文件解析建議:
factory.setExpandEntityReferences(false) 禁用實體擴展。創建元素需:doc.createElement -> setAttribute -> appendChild -> doc.createTextNode -> appendChild。這正是第三方庫簡化的重點。
| 庫 | 特點 | 適用場景 |
|---|---|---|
| Dom4j | XPath 支持、鏈式 API、性能優於 DOM | 企業級項目、複雜 XML 處理 |
| JDOM2 | 純 Java 設計、API 直觀、泛型支持 | 中小型項目、追求代碼可讀性 |
| XStream | 對象<->XML 雙向轉換、註解驅動 | 配置文件、數據序列化 |
| JAXB | 標準規範、註解映射、Schema 驗證 | Web Service、標準化數據交換 |
// Maven: org.dom4j:dom4j:2.1.3
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("books.xml"));
// XPath 一鍵提取
List books = doc.selectNodes("//book");
for (Node book : books) {
String title = book.selectSingleNode("title").getText();
String author = book.selectSingleNode("author").getText();
String id = book.valueOf("@id"); // 屬性快速取值
System.out.println(id + " | " + title + " | " + author);
}
標準 DOM API 是理解 XML 模型的基石,但實際開發中請直接使用 Dom4j 或 JDOM2。僅在「無法引入第三方依賴」、「文件極小(<100KB)」、「需零依賴運行」的受限環境下,才考慮手寫原生 DOM 代碼。記住:工具是為業務服務的,別在 API 細節裡迷失。