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

[JAVA100例] 第69例:使用 SAX 解析 XML——事件驅動流式解析

     編輯:Java 相關知識

本例包含兩個完整 SAX 解析示例:一個針對特定業務數據提取(ReadXmlDemo),一個通用的全事件打印解析器。SAX 採用事件驅動、流式處理,適合大文件、低內存場景。

示例一:業務數據提取

import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

public class ReadXmlDemo extends DefaultHandler {
  public static void main(String[] arguments) {
    if (arguments.length > 0) new ReadXmlDemo(arguments[0]);
    else System.out.println("Usage: java ReadXmlDemo filename");
  }

  ReadXmlDemo(String xmlFile) {
    File input = new File(xmlFile);
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setValidating(true);
    try {
      SAXParser sax = factory.newSAXParser();
      sax.parse(input, new XmlHandler());
    } catch (ParserConfigurationException | SAXException | IOException e) {
      e.printStackTrace();
    }
  }
}

class XmlHandler extends DefaultHandler {
  static final int READING_NAME = 1, READING_SEX = 2, READING_BIRTH = 3, READING_NOTHING = 0;
  int currentActivity = READING_NOTHING;
  ReadXml xml = new ReadXml();

  public void startElement(String uri, String localName, String qName, Attributes attributes) {
    if (qName.equals("title")) currentActivity = READING_NAME;
    else if (qName.equals("file")) currentActivity = READING_SEX;
  }

  public void characters(char[] ch, int start, int length) {
    String value = new String(ch, start, length);
    if (currentActivity == READING_NAME) xml.name = value;
    if (currentActivity == READING_SEX) xml.sex = value;
  }

  public void endElement(String uri, String localName, String qName) {
    if (qName.equals("page")) {
      System.out.println("\nName: " + xml.name);
      System.out.println("Sex: " + xml.sex);
      xml = new ReadXml();  // 重置供下一條記錄
    }
  }
}

class ReadXml { String name, sex, birth; }

示例二:通用全事件打印解析器

import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import java.io.*;

public class SaxParsePage extends DefaultHandler {
  public static void main(String[] argv) {
    try {
      SAXParserFactory spfactory = SAXParserFactory.newInstance();
      SAXParser parser = spfactory.newSAXParser();
      parser.parse(new File("book.xml"), new SaxParsePage());
    } catch (Exception e) { e.printStackTrace(); }
  }

  public void startDocument() { System.out.println("***開始解析***"); }

  public void startElement(String uri, String localName, String qName, Attributes attributes) 
      throws SAXException {
    System.out.println("節點開始:" + qName);
    for (int i = 0; i < attributes.getLength(); i++) {
      System.out.println("節點屬性名稱:" + attributes.getQName(i));
      System.out.println("節點屬性值:" + attributes.getValue(i));
    }
  }

  public void characters(char[] ch, int offset, int length) throws SAXException {
    System.out.println("節點數據:" + new String(ch, offset, length));
  }

  public void endElement(String uri, String localName, String qName) {
    System.out.println("節點結束:" + qName);
  }

  public void endDocument() { System.out.println("****文件解析完畢****"); }
}

SAX 核心事件回調

方法觸發時機典型用途
startDocument()文檔開始初始化狀態
startElement()遇到開始標籤記錄元素名、屬性、切換狀態機
characters()標籤間文本內容提取數據(注意可能分多次調用)
endElement()遇到結束標籤完成數據組裝、輸出、重置狀態
endDocument()文檔結束清理資源、最終輸出

關鍵設計模式:狀態機

示例一中 currentActivity 狀態變量追蹤當前解析上下文,配合 startElement 切換狀態、characters 提取數據、endElement 完成記錄。這是 SAX 處理複雜結構的標準模式。

SAX vs DOM 對比

維度SAXDOM
內存佔用極低(流式)高(全量樹)
解析速度快較慢
隨機訪問不支持支持
編程模式事件回調/狀態機樹遍歷/遞歸
適用場景大文件、單次遍歷、提取特定數據小文件、多次查詢、需修改樹結構

現代 JDK 使用提示

  • JDK 內置 javax.xml.parsers 無需額外依賴
  • 線程不安全:SAXParser 不可共享,每線程創建實例
  • 大文件建議關閉驗證 factory.setValidating(false) 提升性能
  • 編碼問題:確保 XML 聲明編碼與實際文件一致,或使用 InputSource.setEncoding()
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved