SAX,全称Simple API for XML,是一种以事件驱动的XMl API,是XML解析的一种新的替代方法,解析XML常用的还有DOM解析,PULL解析(Android特有)。
SAX与DOM不同的是,SAX解析方式会逐行地去扫描XML文档,当遇到标签时会触发解析处理器,采用事件处理的方式解析XML 。在读取文档的同时即可对XML进行处理,不必等到文档加载结束,相对快捷。不需要加载进内存,因此不存在占用内存的问题,可以解析超大XML。所以它解析XML具有速度快,占用内存少的优点,对于Android等CPU资源宝贵的移动平台来说是一个巨大的优势。缺点是:只能用来读取XML中数据,无法进行增删改。
- SAX解析的优点
- 解析速度快。
- 占用内存少。
- SAX解析的缺点
- 无法知道当前解析标签(节点)的上层标签,及其嵌套结构,仅仅知道当前解析的标签的名字和属性。
- 只能读取XML中数据,无法进行增删改。
- 无法随机访问某个标签(节点)。
SAX解析xml的步骤:
- 得到xml文件对应的资源,可以是xml的输入流,文件和uri。
BufferedInputStream bufStream = getConfigStream(name);
- 得到SAX解析工厂(SAXParserFactory)。
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
- 由解析工厂生产一个SAX解析器(SAXParser)。
SAXParser parser = parserFactory.newSAXParser();
- 传入输入流和handler给解析器,调用parse()解析。
ConfigHandler configHandler =
new ConfigHandler(
configDef, name, mConfigDefLoader, mParentDeviceObject, templateMap);
parser.parse(new InputSource(xmlInput), configHandler);
Handler的5个主要的回调方法:
用SAX解析XML文档的时候,在读取到文档开始和结束标签时候就会回调一个事件,在读到其他节点与内容的时候也会回调一个事件。
2. startDocument() 文档解析开始事回调
3. startElement(String uri, String localName, String qName, Attributes attributes) 读取到节点的开始标签时回调
1. uri:xml文档的命名空间
2. localName:标签的名字
3. qName:带命名空间的标签的名字
4. attributes:标签的属性集
4. characters(char[] ch, int start, int length)读取到标签的内容时回调
1. ch:当前读取到的TextNode(文本节点)的字节数组
2. start:字节开始的位置,为0则读取全部
3. length:当前TextNode的长度
5. endElement(String uri, String localName, String qName)读取到节点的结束标签时回调
6. endDocument()文档解析结束时回调
sax simple API for XML,现在有两个版本:
- sax. 不支持LocalName、QName和uri。对于属性sina:blog=“blog.sina.com”,sax解析的结果是LocalName=QName=“sina:blog”,uri="",value=“blog.sina.com”。
- sax2. 支持LocalName、QName、uri。对于属性sina:blog=“blog.sina.com”,sax2解析的结果是LocalName=“blog”,QName=“sina:blog”,uri="",value=“blog.sina.com”。
SAX的实现方式:
import java.io.StringReader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class XmlSaxParser {
public static void main(String... args) {
try {
String config
= "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<websites"
+ " xmlns:sina=\"http://www.sina.com\""
+ " xmlns:baidu=\"http://www.baidu.com\">"
+ " <sina:website sina:blog=\"blog.sina.com\">新浪</sina:website>"
+ " <baidu:website baidu:blog=\"hi.baidu.com\">百度</baidu:website>"
+ "</websites>";
//sax1解析XML文档
System.out.println("parse xml file use sax");
SaxParseHandler saxHandler = new SaxParseHandler();
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.parse(new InputSource(new StringReader(config)), saxHandler);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class SaxParseHandler extends DefaultHandler{
/**
* 重写了DefaultHandler中的startElement函数,每解析到
* 一个元素(element)的时候都会触发这个函数,并且将这个element
* 的属性attributes和值value当作参数传进来。除了startElement,
* 还有startDocument,endDOucment,endElement,要根据需要
* 重写这些函数。
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
//打印element的基本信息,qName
System.out.println("Element qName : "+qName);
System.out.println("Element localName: "+localName);
System.out.println("Element uri : "+uri);
//打印element的所有属性attributes
for(int i=0; i<attributes.getLength(); i++) {
System.out.println("");
System.out.println(" attribute qName : "+attributes.getQName(i));
System.out.println(" attribute localName: "+attributes.getLocalName(i));
System.out.println(" attribute value : "+attributes.getValue(i));
System.out.println(" attribute uri : "+attributes.getURI(i));
}
System.out.println("");
super.startElement(uri, localName, qName, attributes);
}
}
SAX2的第一种实现方式:
import java.io.StringReader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class XmlSaxParser {
public static void main(String... args) {
try {
String config
= "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<websites"
+ " xmlns:sina=\"http://www.sina.com\""
+ " xmlns:baidu=\"http://www.baidu.com\">"
+ " <sina:website sina:blog=\"blog.sina.com\">新浪</sina:website>"
+ " <baidu:website baidu:blog=\"hi.baidu.com\">百度</baidu:website>"
+ "</websites>";
//sax1解析XML文档
System.out.println("parse xml file use sax");
SaxParseHandler saxHandler = new SaxParseHandler();
SAXParserFactory factory=SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
SAXParser parser = factory.newSAXParser();
parser.parse(new InputSource(new StringReader(config)), saxHandler);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class SaxParseHandler extends DefaultHandler{
/**
* 重写了DefaultHandler中的startElement函数,每解析到
* 一个元素(element)的时候都会触发这个函数,并且将这个element
* 的属性attributes和值value当作参数传进来。除了startElement,
* 还有startDocument,endDOucment,endElement,要根据需要
* 重写这些函数。
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
//打印element的基本信息,qName
System.out.println("Element qName : "+qName);
System.out.println("Element localName: "+localName);
System.out.println("Element uri : "+uri);
//打印element的所有属性attributes
for(int i=0; i<attributes.getLength(); i++) {
System.out.println("");
System.out.println(" attribute qName : "+attributes.getQName(i));
System.out.println(" attribute localName: "+attributes.getLocalName(i));
System.out.println(" attribute value : "+attributes.getValue(i));
System.out.println(" attribute uri : "+attributes.getURI(i));
}
System.out.println("");
super.startElement(uri, localName, qName, attributes);
}
}
SAX2的第二种实现方式(deprecated API):
import java.io.StringReader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class XmlSaxParser {
public static void main(String... args) {
try {
String config
= "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<websites"
+ " xmlns:sina=\"http://www.sina.com\""
+ " xmlns:baidu=\"http://www.baidu.com\">"
+ " <sina:website sina:blog=\"blog.sina.com\">新浪</sina:website>"
+ " <baidu:website baidu:blog=\"hi.baidu.com\">百度</baidu:website>"
+ "</websites>";
//Sax2解析XML文档
System.out.println("parse xml file use sax2");
SaxParseHandler sax2Handler = new SaxParseHandler();
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setContentHandler(sax2Handler);
StringReader fileReader = new StringReader(config);
xmlReader.parse(new InputSource(fileReader));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class SaxParseHandler extends DefaultHandler{
/**
* 重写了DefaultHandler中的startElement函数,每解析到
* 一个元素(element)的时候都会触发这个函数,并且将这个element
* 的属性attributes和值value当作参数传进来。除了startElement,
* 还有startDocument,endDOucment,endElement,要根据需要
* 重写这些函数。
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
//打印element的基本信息,qName
System.out.println("Element qName : "+qName);
System.out.println("Element localName: "+localName);
System.out.println("Element uri : "+uri);
//打印element的所有属性attributes
for(int i=0; i<attributes.getLength(); i++) {
System.out.println("");
System.out.println(" attribute qName : "+attributes.getQName(i));
System.out.println(" attribute localName: "+attributes.getLocalName(i));
System.out.println(" attribute value : "+attributes.getValue(i));
System.out.println(" attribute uri : "+attributes.getURI(i));
}
System.out.println("");
super.startElement(uri, localName, qName, attributes);
}
}
TF框架中,使用SAX2解析config文件。
import java.io.StringReader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class XmlSaxParser {
/**
* 1.首先生成一个SAX解析器工厂实例
* 2.使用工厂来生成一个SAX解析器
* 3.生成XMLReader用来读取XML文件
* 4.在XMLReader对象上面注册内容事件处理程序
* 5.开始解析XML
**/
public static void main(String[] args){
try{
String config
= "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<configuration description=\"Multi device parsing\">"
+ " <device name=\"device1\">"
+ " <build_provider class=\"com.android.tradefed.build.StubBuildProvider\">"
+ " <option name=\"build-id\" value=\"10\" />"
+ " </build_provider>"
+ " </device>"
+ " <device name=\"device2\" >"
+ " <build_provider class=\"com.android.tradefed.build.StubBuildProvider\" />"
+ " <target_preparer class=\"com.android.tradefed.targetprep.StubTargetPreparer\" />"
+ " </device>"
+ " <device name=\"device3\" >"
+ " <build_provider class=\"com.android.tradefed.build.StubBuildProvider\">"
+ " <option name=\"build-flavor\" value=\"build-flavor3\" />"
+ " </build_provider>"
+ " <target_preparer class=\"com.android.tradefed.targetprep.StubTargetPreparer\" />"
+ " <target_preparer class=\"com.android.tradefed.targetprep.DeviceWiper\">"
+ " <option name=\"disable\" value=\"true\" />"
+ " </target_preparer>"
+ " </device>"
+ " <template-include name=\"preparers\" default=\"empty\" />"
+ " <logger class=\"com.android.tradefed.log.FileLogger\" />"
+ " <test class=\"com.android.tradefed.config.StubOptionTest\">"
+ " <option name=\"option\" value=\"valueFromTestConfig\" />"
+ " </test>"
+ "</configuration>";
//生成SAX的解析器工厂的实例
SAXParserFactory factory=SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
SAXParser parser = factory.newSAXParser();
//开始解析
parser.parse(new InputSource(new StringReader(config)), new MyHandlerContent());
}catch(Exception e){
e.printStackTrace();
}
}
}
/**
* 内容事件的处理程序,继承自DefaultHandler。
*
*/
class MyHandlerContent extends DefaultHandler{
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("********************start parse config via SAX2********************");
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("********************end parse config via SAX2********************");
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
System.out.print("<" + localName);
for(int i=0;i<attributes.getLength();i++){
System.out.print(" " + attributes.getLocalName(i) + "=\"" + attributes.getValue(i) + "\"");
}
System.out.println(">");
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
System.out.println("</" + localName + ">");
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
}
}