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 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 cn.org.kingdom.sax; import java.io.File; 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("src/persons.xml"), new MyHandler()); } } class MyHandler extends DefaultHandler { @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: " + new String()); 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); } }
解析代码2
package cn.org.kingdom.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("src/test.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(); } } }
输出结果
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