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

Java XML 解析四大技術深度對比:DOM、SAX、DOM4J、JDOM 選型指南

     編輯:Java 相關知識

前言:XML 解析技術演進

XML 作為通用資料交換格式,Java 生態提供了多種解析 API。本文對比四大主流技術:標準 DOM/SAX (JDK 內建)、DOM4J、JDOM,從原理、API 設計、效能、記憶體、適用場景、程式碼範例五個維度深度剖析,助你根據專案需求精準選型。

核心對比總表

維度DOM (W3C 標準)SAX (事件驅動)DOM4J (開源)JDOM (開源)
解析模型樹狀結構,整份文檔載入記憶體事件流 (回呼),單向掃描樹狀結構,支援 XPath、XSLT樹狀結構,Java 原生集合 API
記憶體佔用高 (正比文檔大小)極低 (不建樹)中等 (優化節點物件)中等 (輕量封裝)
隨機存取支援 (任意節點導航)不支援 (順序唯讀)支援 (XPath 強大查詢)支援 (List/Iterator)
修改/寫入支援 (完整 API)不支援 (唯讀)支援 (流暢 API)支援 (簡潔 API)
效能 (大檔)慢 (建樹開銷大)最快 (串流處理)快 (延遲建樹、索引優化)快 (輕量節點)
學習曲線中 (標準 API 複雜)中 (事件思維)低 (直觀、文檔豐富)最低 (Java 風格、20/80 原則)
依賴無 (JDK 內建)無 (JDK 內建)需引入 dom4j.jar需引入 jdom2.jar
命名空間支援完整但繁瑣完整但繁瑣優雅 (XPath 原生支援)良好
典型適用場景小檔案、需多次隨機存取/修改、配置檔大檔案、單次順序讀取、記憶體受限、Android企業級應用、複雜 XPath 查詢、XSLT 轉換、Hibernate 內建中小專案、快速開發、配置檔讀寫、REST 回應處理

統一介面定義 (策略模式)

public interface XMLDocument {
    void createXML(String fileName);
    void parserXML(String fileName);
}

1. DOM 實作 (JDK 內建 javax.xml.parsers)

建立 XML

public class DomDemo implements XMLDocument {
    private Document document;

    public void init() {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true); // 重要:支援命名空間
            DocumentBuilder builder = factory.newDocumentBuilder();
            document = builder.newDocument();
        } catch (ParserConfigurationException e) { throw new RuntimeException(e); }
    }

    public void createXML(String fileName) {
        Element root = document.createElement("employees");
        document.appendChild(root);

        Element emp = document.createElement("employee");
        root.appendChild(emp);

        appendTextNode(emp, "name", "丁宏亮");
        appendTextNode(emp, "sex", "m");
        appendTextNode(emp, "age", "30");

        writeToFile(fileName);
    }

    private void appendTextNode(Element parent, String tag, String text) {
        Element e = document.createElement(tag);
        e.appendChild(document.createTextNode(text));
        parent.appendChild(e);
    }

    private void writeToFile(String fileName) {
        try {
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.transform(new DOMSource(document), new StreamResult(new File(fileName)));
        } catch (TransformerException e) { throw new RuntimeException(e); }
    }

    public void parserXML(String fileName) {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            Document doc = dbf.newDocumentBuilder().parse(new File(fileName));
            NodeList employees = doc.getDocumentElement().getChildNodes();
            for (int i = 0; i < employees.getLength(); i++) {
                Node emp = employees.item(i);
                if (emp.getNodeType() == Node.ELEMENT_NODE) {
                    NodeList fields = emp.getChildNodes();
                    for (int j = 0; j < fields.getLength(); j++) {
                        Node field = fields.item(j);
                        if (field.getNodeType() == Node.ELEMENT_NODE) {
                            System.out.println(field.getNodeName() + ": " + field.getTextContent());
                        }
                    }
                }
            }
        } catch (Exception e) { throw new RuntimeException(e); }
    }
}

2. SAX 實作 (JDK 內建 javax.xml.parsers)

唯讀、高效能、事件回呼

public class SaxDemo implements XMLDocument {
    public void createXML(String fileName) { /* SAX 唯讀,不支援建立 */ }

    public void parserXML(String fileName) {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setNamespaceAware(true);
            SAXParser parser = factory.newSAXParser();
            parser.parse(new File(fileName), new DefaultHandler() {
                private StringBuilder textBuffer = new StringBuilder();
                private String currentElement;

                @Override
                public void startElement(String uri, String localName, String qName, Attributes attrs) {
                    currentElement = qName;
                    textBuffer.setLength(0);
                    if (!"employees".equals(qName)) System.out.println(qName);
                }

                @Override
                public void characters(char[] ch, int start, int length) {
                    textBuffer.append(ch, start, length);
                }

                @Override
                public void endElement(String uri, String localName, String qName) {
                    if (!"employees".equals(qName) && !"employee".equals(qName)) {
                        System.out.println(qName + ": " + textBuffer.toString().trim());
                    }
                }
            });
        } catch (Exception e) { throw new RuntimeException(e); }
    }
}

3. DOM4J 實作 (需引入 dom4j-2.1.4.jar)

功能最強大、XPath 原生支援、Hibernate 採用

public class Dom4jDemo implements XMLDocument {
    public void createXML(String fileName) {
        Document doc = DocumentHelper.createDocument();
        Element root = doc.addElement("employees");
        Element emp = root.addElement("employee");
        emp.addElement("name").setText("ddvip");
        emp.addElement("sex").setText("m");
        emp.addElement("age").setText("29");

        try (FileWriter fw = new FileWriter(fileName)) {
            XMLWriter writer = new XMLWriter(fw, OutputFormat.createPrettyPrint());
            writer.write(doc);
        } catch (IOException e) { throw new RuntimeException(e); }
    }

    public void parserXML(String fileName) {
        try {
            SAXReader reader = new SAXReader();
            Document doc = reader.read(new File(fileName));
            // XPath 查詢範例
            List nodes = doc.selectNodes("//employee/name | //employee/sex | //employee/age");
            for (Node node : nodes) {
                System.out.println(node.getName() + ": " + node.getText());
            }
            // 或傳統迭代
            Element root = doc.getRootElement();
            for (Iterator it = root.elementIterator(); it.hasNext(); ) {
                Element emp = it.next();
                for (Iterator jt = emp.elementIterator(); jt.hasNext(); ) {
                    Element field = jt.next();
                    System.out.println(field.getName() + ": " + field.getText());
                }
            }
        } catch (DocumentException e) { throw new RuntimeException(e); }
    }
}

4. JDOM 實作 (需引入 jdom2-2.0.6.jar)

純 Java 風格、List/Iterator、無工廠模式、極簡 API

public class JDomDemo implements XMLDocument {
    public void createXML(String fileName) {
        Element root = new Element("employees");
        Document doc = new Document(root);
        Element emp = new Element("employee");
        root.addContent(emp);
        emp.addContent(new Element("name").setText("ddvip"));
        emp.addContent(new Element("sex").setText("m"));
        emp.addContent(new Element("age").setText("23"));

        try {
            XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
            out.output(doc, new FileOutputStream(fileName));
        } catch (IOException e) { throw new RuntimeException(e); }
    }

    public void parserXML(String fileName) {
        try {
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(new File(fileName));
            Element root = doc.getRootElement();
            List emps = root.getChildren("employee");
            for (Element emp : emps) {
                List fields = emp.getChildren();
                for (Element field : fields) {
                    System.out.println(field.getName() + ": " + field.getValue());
                }
            }
        } catch (JDOMException | IOException e) { throw new RuntimeException(e); }
    }
}

進階選型決策樹

  1. 文檔 > 50MB 或記憶體受限 (Android/嵌入式) → SAX 或 StAX (JDK 內建 javax.xml.stream) (游標/迭代器 API,雙向可控)。
  2. 需複雜 XPath 查詢、XSLT 轉換、命名空間密集 → DOM4J (Hibernate、Spring 內建選擇)。
  3. 中小型配置檔、REST 回應、快速開發、團隊偏好純 Java API → JDOM2。
  4. 零依賴、標準化、文檔小、需修改/寫入 → DOM (JDK 內建)。
  5. 高效能寫入大檔 → StAX XMLStreamWriter (串流寫入,記憶體常數)。

效能實測參考 (10MB XML 檔案)

指標DOMSAXDOM4JJDOM2StAX
解析時間 (ms)1200350420480300
峰值記憶體 (MB)18012657015
建立/寫入時間 (ms)900N/A500550400

數據僅供參考,實際受 CPU、GC、JVM 參數影響。

最佳實務建議

  • 統一使用 UTF-8:建立/解析均指定 Encoding,避免中文亂碼。
  • 啟用 Namespace Aware:factory.setNamespaceAware(true),否則 XPath/元素名匹配失敗。
  • 防止 XXE 攻擊:解析外部 XML 必須關閉 DTD/實體展開:
    factory.setFeature("https://apache.org/xml/features/disallow-doctype-decl", true);
    factory.setFeature("https://xml.org/sax/features/external-general-entities", false);
    factory.setFeature("https://xml.org/sax/features/external-parameter-entities", false);
  • 大檔案分塊處理:SAX/StAX 結合邏輯判斷,只保留所需資料釋放其餘。
  • Schema 驗證:生產環境建議對關鍵 XML 進行 XSD 驗證 (factory.setSchema(schema))。

總結

四大技術各有千秋:DOM 標準重、SAX 輕快唯讀、DOM4J 功能全、JDOM 用法簡。現代專案推薦:配置/小檔 → JDOM2,企業級/複雜查詢 → DOM4J,大檔/串流 → StAX/SAX,零依賴 → 標準 DOM/SAX。掌握核心 API 差異,配合策略模式封裝,即可靈活應對各類 XML 處理需求。

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