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

Java 與 XML 聯合編程:SAX 解析器深度解析

     編輯:Java 相關知識

SAX 核心概念

SAX(Simple API for XML)並非 W3C 官方標準,而是由開發社群共同推動的事實標準。儘管出身「民間」,它在 XML 解析領域的地位絲毫不遜於 DOM,幾乎所有主流 XML 解析器皆提供支援。

與 DOM 需將整份文檔載入記憶體構建樹狀結構不同,SAX 採用事件驅動、流式處理機制。解析器邊讀取 XML 邊觸發事件(如元素開始、字符內容、元素結束),透過回調函數交由開發者實現的 ContentHandler 處理。這意味著:

  • 記憶體佔用極低,適合大型 XML 文件或資源受限環境(如 Applet)。
  • 無法隨機存取節點,開發者需自行維護文檔結構(常用堆疊記錄層級)。
  • 編程模型較 DOM 複雜,但效能顯著更優。

核心接口與關鍵方法

org.xml.sax.ContentHandler 是 SAX 處理的核心介面,主要方法包括:

方法觸發時機說明
startDocument()文檔開始初始化資源、重置狀態
endDocument()文檔結束釋放資源、輸出結果
startElement(uri, localName, qName, attrs)遇到開始標籤取得元素名稱與屬性列表 attrs
endElement(uri, localName, qName)遇到結束標籤標記該元素處理完畢
characters(ch, start, length)讀到字符內容需自行從字符陣列提取字串:new String(ch, start, length)

實務上常繼承 DefaultHandler(已實作所有方法為空),僅覆寫需要的方法,簡化開發。

實戰範例一:統計標籤出現次數

public class SAXCounter extends DefaultHandler {
    private Map<String, Integer> tags = new HashMap<>();

    @Override
    public void startDocument() { tags.clear(); }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attrs) {
        tags.merge(localName, 1, Integer::sum);
    }

    @Override
    public void endDocument() {
        tags.forEach((tag, count) -> System.out.println("Tag <" + tag + "> occurs " + count + " times"));
    }

    public static void main(String[] args) throws Exception {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser parser = spf.newSAXParser();
        parser.parse(new File("links.xml"), new SAXCounter());
    }
}

關鍵點:

  1. 使用 SAXParserFactory 解耦具體解析器實現(工廠模式)。
  2. SAXParser 封裝了 XMLReader,提供更豐富的 parse() 多載。

實戰範例二:結構化讀取並格式化輸出

由於 SAX 不保留父子關係,若需根據層級判斷語義(如只在 <link> 結束時輸出),需自行維護堆疊:

public class SAXReader extends DefaultHandler {
    private Deque<String> tagStack = new ArrayDeque<>();
    private String text, url, author, description, day, month, year;

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attrs) {
        tagStack.push(localName);
    }

    @Override
    public void endElement(String uri, String localName, String qName) {
        tagStack.pop();
        if ("link".equals(localName)) printOut(); // 一筆資料收集完畢
    }

    @Override
    public void characters(char[] ch, int start, int length) {
        String currentTag = tagStack.peek();
        String value = new String(ch, start, length);
        switch (currentTag) {
            case "text": text = value; break;
            case "url": url = value; break;
            case "author": author = value; break;
            case "day": day = value; break;
            case "month": month = value; break;
            case "year": year = value; break;
            case "description": description = value; break;
        }
    }

    private void printOut() {
        System.out.println("Content: " + text);
        System.out.println("URL: " + url);
        System.out.println("Author: " + author);
        System.out.println("Date: " + day + "-" + month + "-" + year);
        System.out.println("Description: " + description);
        System.out.println();
    }
    // main 方法同範例一,改用 saxParser.parse(file, new SAXReader())
}

堆疊底部到頂部即為從根節點到當前節點的唯一路徑,若需精確判斷位置,可遍歷堆疊(Vector 繼承關係允許隨機存取)。

總結:DOM vs SAX 選型指南

維度DOMSAX
記憶體佔用高(整樹駐留)極低(流式)
隨機存取支援不支援
編程複雜度低中高(需自管狀態)
適用場景小檔案、頻繁修改、XPath 查詢大檔案、單向讀取、記憶體敏感環境

兩者皆為語言中立標準,Java 只是眾多實現語言之一。實務上常搭配使用:SAX 快速篩選感興趣片段,再以 DOM 精細操作。

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