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

Java XML 解析四大主流方式全方位對比與實戰指南

     編輯:Java 相關知識

前言

XML 作為企業級應用中經久不衰的資料交換格式,Java 生態提供了多種解析技術。本文系統梳理 DOM、SAX、JDOM、Dom4j 四大主流解析方式的核心原理、適用場景、程式碼實戰與優劣對比,助你根據專案需求做出最佳技術選型。

核心原理對比總覽

維度DOMSAXJDOMDom4j
解析模式樹模型(一次性載入全文檔)事件驅動(流式單向讀取)樹模型(輕量級封裝)樹模型(高效能實作)
記憶體佔用高(正比文檔大小)極低(不載入樹)中等中等偏低
隨機存取支援完整不支援(單向流)支援支援
修改/寫入支援不支援(唯讀)支援支援
XPath 支援需額外庫不支援有限支援原生完整支援
學習曲線平緩陡峭(回調思維)平緩平緩
適用文檔大小< 10MB任意大小(GB 級)< 50MB< 100MB

1. DOM (Document Object Model) - W3C 標準樹模型

核心特點

  • 將整個 XML 文檔載入記憶體構建 DOM 樹,佔用記憶體與文檔大小成正比
  • 提供隨機存取:可任意導航父/子/兄弟節點、屬性、文本
  • 支援完整的增刪改查,可將修改後的樹寫回 XML 檔案
  • JDK 內建 javax.xml.parsers,無第三方依賴

基礎解析範例

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.File;

public class DomParseDemo {
    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("candidate.xml"));

        // 3. 獲取所有 PERSON 元素
        NodeList personList = doc.getElementsByTagName("PERSON");

        // 4. 遍歷提取資料
        for (int i = 0; i < personList.getLength(); i++) {
            Element person = (Element) personList.item(i);
            String name = getTextContent(person, "NAME");
            String email = getTextContent(person, "EMAIL");
            System.out.printf("姓名: %s, Email: %s%n", name, email);
        }
    }

    private static String getTextContent(Element parent, String tagName) {
        NodeList list = parent.getElementsByTagName(tagName);
        if (list.getLength() > 0) {
            Node child = list.item(0).getFirstChild();
            return child != null ? child.getNodeValue() : "";
        }
        return "";
    }
}

遞歸通用解析(處理任意結構)

private static void parseElement(Element element) {
    System.out.print("<" + element.getTagName());
    
    // 處理屬性
    NamedNodeMap attrs = element.getAttributes();
    if (attrs != null) {
        for (int i = 0; i < attrs.getLength(); i++) {
            Attr attr = (Attr) attrs.item(i);
            System.out.print(" " + attr.getName() + "=\"" + attr.getValue() + "\"");
        }
    }
    System.out.print(">");

    // 遞歸處理子節點
    NodeList children = element.getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
        Node node = children.item(i);
        switch (node.getNodeType()) {
            case Node.ELEMENT_NODE:
                parseElement((Element) node);
                break;
            case Node.TEXT_NODE:
                System.out.print(node.getNodeValue().trim());
                break;
            case Node.COMMENT_NODE:
                System.out.print("<!--" + node.getNodeValue() + "-->");
                break;
        }
    }
    System.out.print("</" + element.getTagName() + ">");
}

2. SAX (Simple API for XML) - 事件驅動流式解析

核心特點

  • 不建立樹結構,邊讀邊解析,記憶體佔用極低,適合超大文檔
  • 單向流:無法回溯、無法修改、無法隨機存取
  • 透過 DefaultHandler 回調方法處理事件:startElement、characters、endElement
  • 開發者需自行維護上下文狀態(如用 Stack 追蹤元素巢狀層級)

基礎 Handler 實作

import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.util.Stack;

public class SaxParseDemo {
    public static void main(String[] args) throws Exception {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setNamespaceAware(true);
        SAXParser parser = factory.newSAXParser();
        parser.parse(new File("student.xml"), new StudentHandler());
    }
}

class StudentHandler extends DefaultHandler {
    private Stack elementStack = new Stack<>();
    private String name, gender, age;

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attrs) {
        elementStack.push(qName);
        // 處理屬性
        for (int i = 0; i < attrs.getLength(); i++) {
            System.out.println(attrs.getQName(i) + "=" + attrs.getValue(i));
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) {
        String currentTag = elementStack.peek();
        String value = new String(ch, start, length).trim();
        if (value.isEmpty()) return;
        
        switch (currentTag) {
            case "姓名": name = value; break;
            case "性別": gender = value; break;
            case "年齡": age = value; break;
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) {
        elementStack.pop();
        if ("學生".equals(qName)) { // 一個學生元素結束
            System.out.printf("姓名: %s, 性別: %s, 年齡: %s%n", name, gender, age);
            name = gender = age = null;
        }
    }
}

3. JDOM - Java 原生優化樹模型

核心特點

  • 純 Java 實作,API 設計符合 Java 慣用語(大量使用 Collections、方法重載)
  • 僅使用具體類別而非介面,簡化 API 但犧牲部分擴充性
  • 內建 SAXBuilder/DOMBuilder 靈活切換底層解析器
  • 支援輸出格式化(Format.getPrettyFormat())、XPath(需 Jaxen)

Maven 依賴

<dependency>
    <groupId>org.jdom</groupId>
    <artifactId>jdom2</artifactId>
    <version>2.0.6.1</version>
</dependency>

建立 XML 文檔

import org.jdom2.*;
import org.jdom2.output.*;

public class JDomCreateDemo {
    public static void main(String[] args) throws Exception {
        Document doc = new Document();
        Element root = new Element("root");
        doc.setRootElement(root);

        root.addContent(new Comment("這是註解"));
        
        Element hello = new Element("hello");
        hello.setAttribute("source", "www.sohu.com");
        root.addContent(hello);

        Element world = new Element("world");
        world.setAttribute(new Attribute("test", "hehe"));
        hello.addContent(world);

        world.addContent(new Element("aaa")
            .setAttribute("a", "b")
            .setAttribute("x", "y")
            .setText("text content"));

        // 格式化輸出
        Format format = Format.getPrettyFormat();
        format.setIndent("    ");
        new XMLOutputter(format).output(doc, new FileWriter("jdom.xml"));
    }
}

解析與修改 XML

public class JDomParseDemo {
    public static void main(String[] args) throws Exception {
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(new File("jdom.xml"));
        
        Element root = doc.getRootElement();
        Element hello = root.getChild("hello");
        
        // 讀取屬性
        for (Attribute attr : hello.getAttributes()) {
            System.out.println(attr.getName() + "=" + attr.getValue());
        }
        
        // 修改:移除子元素並寫回
        hello.removeChild("world");
        new XMLOutputter(Format.getPrettyFormat().setIndent("    "))
            .output(doc, new FileOutputStream("jdom2.xml"));
    }
}

4. Dom4j - 功能最全、效能最強的 XML 框架

核心特點

  • 介面導向設計,支援並行存取(Dom4j API + 標準 DOM 介面)
  • 原生整合 XPath、XML Schema 驗證、大文檔流式處理(SAXReader)
  • 廣泛應用於 Hibernate、Spring、JAXM 等知名框架
  • 效能優於 JDOM,靈活度最高

Maven 依賴

<dependency>
    <groupId>org.dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>2.1.4</version>
</dependency>

建立文檔(多種方式)

import org.dom4j.*;
import org.dom4j.io.*;

public class Dom4jCreateDemo {
    public static void main(String[] args) throws Exception {
        // 方式 1: DocumentHelper 建立
        Element root = DocumentHelper.createElement("student");
        Document doc = DocumentHelper.createDocument(root);
        
        root.addAttribute("name", "zhangsan");
        Element hello = root.addElement("hello").addAttribute("age", "20").setText("hello");
        root.addElement("world").setText("world");

        // 格式化輸出到檔案
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setIndent("    ");
        new XMLWriter(new FileOutputStream("student2.xml"), format).write(doc);
        
        // 輸出到控制台
        new XMLWriter(OutputFormat.createPrettyPrint()).write(doc);
    }
}

解析與 XPath 查詢

public class Dom4jParseDemo {
    public static void main(String[] args) throws Exception {
        SAXReader reader = new SAXReader();
        Document doc = reader.read(new File("student2.xml"));
        
        Element root = doc.getRootElement();
        System.out.println("根元素: " + root.getName());
        
        // 1. 獲取所有子元素
        List children = root.elements();
        System.out.println("子元素總數: " + children.size());
        
        // 2. 獲取指定名稱子元素
        List helloList = root.elements("hello");
        System.out.println("hello 元素數: " + helloList.size());
        
        // 3. 獲取第一個 hello 元素的屬性
        Element firstHello = root.element("hello");
        System.out.println("age 屬性: " + firstHello.attributeValue("age"));
        
        // 4. 迭代器遍歷
        for (Element e : root.elements()) {
            System.out.println("元素: " + e.getName() + ", age=" + e.attributeValue("age"));
        }
        
        // 5. XPath 查詢(核心優勢)
        // Element node = (Element) doc.selectSingleNode("//hello[@age='20']");
        // List nodes = doc.selectNodes("//world");
        
        // 6. 與標準 DOM 互轉
        DOMReader domReader = new DOMReader();
        org.w3c.dom.Document w3cDoc = DocumentBuilderFactory.newInstance()
            .newDocumentBuilder().parse(new File("student2.xml"));
        Document dom4jDoc = domReader.read(w3cDoc);
    }
}

技術選型決策指南

  1. 文檔 < 10MB、需頻繁隨機存取/修改、無第三方依賴限制 → DOM(JDK 內建,零依賴)
  2. 文檔巨大(> 100MB)、唯讀、單向流式處理、記憶體受限 → SAX(或 StAX:XMLStreamReader,更現代的拉式解析)
  3. 中等文檔、追求開發效率、API 友善、需輕量修改/輸出 → JDOM(適合中小專案快速開發)
  4. 企業級應用、需 XPath/Schema、大文檔流式處理、高效能、框架整合 → Dom4j(綜合實力最強,推薦首選)

現代化補充:StAX (Streaming API for XML)

JDK 6+ 內建 javax.xml.stream,提供 拉式 解析,兼具 SAX 低記憶體與 DOM 的控制流優勢:

XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("data.xml"));
while (reader.hasNext()) {
    int event = reader.next();
    if (event == XMLStreamReader.START_ELEMENT) {
        System.out.println("元素: " + reader.getLocalName());
    } else if (event == XMLStreamReader.CHARACTERS) {
        System.out.println("文本: " + reader.getText());
    }
}
reader.close();

新專案建議優先評估 StAX 或 Dom4j,避免直接使用較底層的 SAX。

總結

XML 解析無絕對最優,只有最適合。理解四大方式的記憶體模型、存取模式、擴充能力三大核心差異,結合文檔大小、業務複雜度、效能指標、團隊熟悉度四大決策因子,即可做出理性技術選型。現代 Java 專案中,Dom4j 與 StAX 是最推薦的兩大主力選擇。

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