XML解析之 SAX解析
SAX介紹
SAX的全稱是Simple APIs for XML,也即XML簡單應用程序接口。
與DOM不同,SAX提供的訪問模式是一種順序模式,這是一種快速讀寫XML數據的方式。
當使用SAX分析器對XML文檔進行分析時,會觸發一系列事件,並激活相應的事件處理函數,應用程序通過這些事件處理函數實現對XML文檔的訪問,因而SAX接口也被稱作事件驅動接口。
局限性:
1. SAX分析器在對XML文檔進行分析時,觸發了一系列的事件,由於事件觸發本身是有時序性的,因此,SAX提供的是一種順序訪問機制,對於已經分析過的部分,不能再倒回去重新處理。
即,一旦經過了某個元素,我們沒有辦法返回去再去訪問它。
2. SAX分析器只做了一些簡單的工作,大部分工作還要由應用程序自己去做。
也就是說,SAX分析器在實現時,只是順序地檢查XML文檔中的字節流,判斷當前字節是XML語法中的哪一部分、是否符合XML語法,然后再觸發相應的事件,而事件處理函數本身則要由應用程序自己來實現。
同DOM分析器相比,SAX分析器缺乏靈活性。
優勢:
然而,由於SAX分析器實現簡單,對內存要求比較低,(SAX不必將整個XML文檔加載到內存當中,因此它占據內存要比DOM小), 因此實現效率比較高。
對於大型的XML文檔來說,通常會用SAX而不是DOM。
並且對於那些只需要訪問XML文檔中的數據而不對文檔進行更改的應用程序來說,SAX分析器更為合適。
SAX分析器
XML解析器實際上就是一段代碼,它讀入一個XML文檔並分析其結構。
分類:
帶校驗的解析器
不校驗的解析器(效率高)
支持DOM的解析器(W3C的官方標准)
支持SAX的解析器(事實上的工業標准)
SAX是事件驅動的,文檔的讀入過程就是SAX的解析過程。
在讀入的過程中,遇到不同的項目,解析器會調用不同的處理方法。
SAX解析實例
以一個xml文檔為例:
<?xml version="1.0" encoding="UTF-8"?> <bookstore> <book category="children"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="cooking"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="web"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> <book category="web"> <title lang="en">XQuery Kick Start</title> <author>James McGovern</author> <author>Per Bothner</author> <author>Kurt Cagle</author> <author>James Linn</author> <author>Vaidyanathan Nagarajan</author> <year>2003</year> <price>49.99</price> </book> </bookstore>
用SAX解析這個文檔的Java代碼:
package com.example.xml.sax; import java.io.File; import java.util.Arrays; import java.util.Stack; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * SAX解析XML * 查看事件調用 * */ public class SaxTest1 { public static void main(String[] args) throws Exception { // step 1: 獲得SAX解析器工廠實例 SAXParserFactory factory = SAXParserFactory.newInstance(); // step 2: 獲得SAX解析器實例 SAXParser parser = factory.newSAXParser(); // step 3: 開始進行解析 // 傳入待解析的文檔的處理器 parser.parse(new File("books.xml"), new MyHandler()); } } class MyHandler extends DefaultHandler { // 使用棧這個數據結構來保存 private Stack<String> stack = new Stack<String>(); @Override public void startDocument() throws SAXException { System.out.println("start document -> parse begin"); } @Override public void endDocument() throws SAXException { System.out.println("end document -> parse finished"); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("start element-----------"); System.out.println(" localName: " + localName); System.out.println(" qName: " + qName); } @Override public void characters(char[] ch, int start, int length) throws SAXException { System.out.println("characters-----------"); // System.out.println(" ch: " + Arrays.toString(ch) ); System.out.println(" ch: " + ch); System.out.println(" start: " + start); System.out.println(" length: " + length); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("end element-----------"); System.out.println(" localName: " + localName); System.out.println(" qName: " + qName); } }
解析程序第二版:

package com.example.xml.sax; import java.io.File; import java.util.Stack; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * SAX解析XML * */ public class SaxTest2 { public static void main(String[] args) throws Exception { // step 1: 獲得SAX解析器工廠實例 SAXParserFactory factory = SAXParserFactory.newInstance(); // step 2: 獲得SAX解析器實例 SAXParser parser = factory.newSAXParser(); // step 3: 開始進行解析 // 傳入待解析的文檔的處理器 parser.parse(new File("books.xml"), new MySAXHandler()); } } class MySAXHandler extends DefaultHandler { // 使用棧這個數據結構來保存 private Stack<String> stack = new Stack<String>(); // 數據 private String title; private String author; private String year; private double price; @Override public void startDocument() throws SAXException { System.out.println("start document -> parse begin"); } @Override public void endDocument() throws SAXException { System.out.println("end document -> parse finished"); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // System.out.println("start element-----------"); // System.out.println(" localName: " + localName); // System.out.println(" qName: " + qName); // 將標簽名壓入棧 stack.push(qName); // 處理屬性 for (int i = 0; i < attributes.getLength(); ++i) { String attrName = attributes.getQName(i); String attrValue = attributes.getValue(i); System.out.println("屬性: " + attrName + "=" + attrValue); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { // System.out.println("characters-----------"); // System.out.println(" ch: " + Arrays.toString(ch) ); // System.out.println(" ch: " + ch); // System.out.println(" start: " + start); // System.out.println(" length: " + length); // 取出標簽名 String tag = stack.peek(); if ("title".equals(tag)) { title = new String(ch, start, length); } else if ("author".equals(tag)) { author = new String(ch, start, length); } else if ("year".equals(tag)) { year = new String(ch, start, length); } else if ("price".equals(tag)) { price = Double.parseDouble(new String(ch, start, length)); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // System.out.println("end element-----------"); // // System.out.println(" localName: " + localName); // System.out.println(" qName: " + qName); stack.pop();// 表示該元素解析完畢,需要從棧中彈出標簽 if ("book".equals(qName)) { System.out.println("Book info: -------"); System.out.println(" title: " + title); System.out.println(" author: " + author); System.out.println(" year: " + year); System.out.println(" price: " + price); System.out.println(); } } }
SaxTest2程序輸出:

start document -> parse begin 屬性: category=children 屬性: lang=en Book info: ------- title: Harry Potter author: J K. Rowling year: 2005 price: 29.99 屬性: category=cooking 屬性: lang=en Book info: ------- title: Everyday Italian author: Giada De Laurentiis year: 2005 price: 30.0 屬性: category=web 屬性: lang=en Book info: ------- title: Learning XML author: Erik T. Ray year: 2003 price: 39.95 屬性: category=web 屬性: lang=en Book info: ------- title: XQuery Kick Start author: Vaidyanathan Nagarajan year: 2003 price: 49.99 end document -> parse finished
參考資料
聖思園張龍老師XML教學視頻。
Java API文檔:http://docs.oracle.com/javase/7/docs/api/index.html