首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java DOM 解析器讀寫 XML 完整教程:從解析到序列化

     編輯:Java 相關知識

DOM 模型核心概念

  • 樹狀結構:整個 XML 文檔加載為內存樹 (Document 根節點)
  • 節點類型:Element、Attribute、Text、Comment、CDATASection 等
  • 優點:隨機訪問、可修改、雙向導航
  • 缺點:內存佔用大 (文檔大小 5-10 倍),不適合超大文件

核心代碼:讀取 → Bean → 寫入新文件

import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class XmlDomDemo {

    // 1. 讀取 XML → 對象列表
    public static List parseBooks(String xmlPath) {
        List list = new ArrayList<>();
        try {
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = builder.parse(new File(xmlPath));

            NodeList bookNodes = doc.getElementsByTagName("book");
            for (int i = 0; i < bookNodes.getLength(); i++) {
                Element bookElem = (Element) bookNodes.item(i);
                BookBean book = new BookBean();
                book.setTitle(getTextContent(bookElem, "title"));
                book.setAuthor(getTextContent(bookElem, "author"));
                book.setPrice(getTextContent(bookElem, "price"));
                list.add(book);
            }
        } catch (Exception e) {
            throw new RuntimeException("XML 解析失敗: " + xmlPath, e);
        }
        return list;
    }

    // 輔助:安全獲取子元素文本內容
    private static String getTextContent(Element parent, String tagName) {
        NodeList nl = parent.getElementsByTagName(tagName);
        if (nl.getLength() > 0) {
            Node node = nl.item(0).getFirstChild();
            return (node != null) ? node.getNodeValue() : "";
        }
        return "";
    }

    // 2. 對象列表 → 寫入新 XML 文件
    public static void writeBooks(List books, String outputPath) {
        try {
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = builder.newDocument();

            // 創建根元素
            Element root = doc.createElement("books");
            doc.appendChild(root);

            for (BookBean book : books) {
                Element bookElem = doc.createElement("book");
                root.appendChild(bookElem);

                appendElement(doc, bookElem, "title", book.getTitle());
                appendElement(doc, bookElem, "author", book.getAuthor());
                appendElement(doc, bookElem, "price", book.getPrice());
            }

            // 序列化輸出 (帶縮進)
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{https://xml.apache.org/xslt}indent-amount", "2");
            transformer.transform(new DOMSource(doc), new StreamResult(new File(outputPath)));

        } catch (Exception e) {
            throw new RuntimeException("XML 寫入失敗: " + outputPath, e);
        }
    }

    // 輔助:創建元素並設置文本
    private static void appendElement(Document doc, Element parent, String tagName, String text) {
        Element elem = doc.createElement(tagName);
        elem.appendChild(doc.createTextNode(text == null ? "" : text));
        parent.appendChild(elem);
    }

    // Bean 類
    public static class BookBean {
        private String title, author, price;
        public String getTitle() { return title; }
        public void setTitle(String title) { this.title = title; }
        public String getAuthor() { return author; }
        public void setAuthor(String author) { this.author = author; }
        public String getPrice() { return price; }
        public void setPrice(String price) { this.price = price; }
    }

    // 測試主方法
    public static void main(String[] args) {
        List books = parseBooks("books.xml");
        System.out.println("解析到 " + books.size() + " 本書");
        writeBooks(books, "new_books.xml");
        System.out.println("寫入完成: new_books.xml");
    }
}

關鍵 API 速查表

任務核心類/方法說明
解析文件DocumentBuilder.parse(File/InputStream)返回 Document 對象
查找元素getElementsByTagName(name)返回 NodeList,按文檔順序
獲取文本node.getFirstChild().getNodeValue()Text 節點的值
創建元素doc.createElement(tagName)需 appendChild 掛載
創建文本doc.createTextNode(content)轉義特殊字符 (< > &)
序列化輸出Transformer.transform(DOMSource, StreamResult)可設置 INDENT 格式化
命名空間doc.createElementNS(nsURI, qualifiedName)處理 xmlns 前綴

現代替代方案對比

方案優點缺點適用場景
DOM (標準)無依賴、樹操作直觀內存大、代碼冗長小文件、需隨機修改
JAXB注解驅動、對象綁定自動化需註解污染領域模型配置文件、API 請響應
Jackson XML高性能、流式、注解豐富第三方依賴高吞吐、微服務通訊
XStream簡單、無注解、支援多態安全性歷史問題 (需 1.4.18+)快速原型、舊系統集成
SAX/StAX流式、低內存、高性能單向只讀、邏輯複雜超大文件 (GB 級)

最佳實踐建議

  1. 小文件 (<10MB):DOM 代碼簡單直觀,無需引入額外依賴
  2. 中大文件/高性能:Jackson XML (XmlMapper) 或 StAX (XMLStreamReader)
  3. 對象綁定:JAXB (Java EE 標準) 或 Jackson 注解
  4. 輸出格式化:transformer.setOutputProperty(OutputKeys.INDENT, "yes") + indent-amount
  5. 異常處理:統一拋出 RuntimeException 携帶文件路徑與原始原因
  6. 編碼:輸出流指定 UTF-8,讀取時 DocumentBuilder 自動識別 XML 声明編碼

總結

DOM 解析器是 Java 標準庫處理 XML 的基石,適合小型文檔的隨機讀寫、修改、生成。核心流程:DocumentBuilder.parse → NodeList 遍歷 → getTextContent → Document 創建樹 → Transformer 序列化。現代項目中,Jackson XML 以高性能、流式處理、豐富注解成為首選;但理解 DOM 基礎 API 對於排查序列化問題、處理舊系統集成、無依賴約束環境仍具不可替代價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved