XML文件常用的解析方式有DOM解析,SAX解析。
一、Sax
SAX(simpleAPIforXML)是一种XML解析的替代方法。相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就是操作复杂。SAX解析XML文档采用事件驱动模式。什么是事件驱动模式?它将XML文档转换成一系列的事件,由单独的事件处理器来决定如何处理。基于事件驱动的处理模式主要是基于事件源和事件处理器(或者叫监听器)来工作的。一个可以产生事件的对象叫做事件源,而一个可以针对事件做出响应的对象就被叫做事件处理器。
在SAX接口中,事件源是org.xml.sax包中的XMLReader,他通过parse()方法开始解析XML文档,并根据文档内容产生事件。而事件处理器则是org.xml.sax包中的ContentHandler、DTDHandler、ErrorHandler,以及EntityResolver这四个接口。他们分别处理事件源在解析过程中产生不同类的事件(其中DTDHandler为解析文档DTD时所用)。详细介绍如下表:
在上述四个接口中,最重要的就是ContentHandler这个接口,下面是对这个接口方法的说明:
实现一个ContentHandler一般要一下几个步骤:
1、声明一个类,继承DefaultHandler。DefaultHandler是一个基类,这个类里面简单实现了一个ContentHandler。我们只需要重写里面的方法即可。
2、重写 startDocument() 和 endDocument(),一般解析将正式解析之前的一些初始化工资放到startDocument()里面,收尾的工作放到endDocument()里面。
3、重写startElement(),XML解析器遇到XML里面的tag时就会调用这个函数。经常在这个函数内是通过localName俩进行判断而操作一些数据。
4、重写characters()方法,这是一个回调方法。解析器执行完startElement()后,解析完节点的内容后就会执行这个方法,并且参数ch[]就是节点的内容。这个例子里我们根据currentstate的不同,来判断当前那个tag的内容,并放到合适的实体类中。
5、重写endElement()方法,这个方法与startElement()相对应,解析完一个tag节点后,执行这个方法。
//设置一个可以定位文档内容事件发生位置的定位器对象 public void setDocumentLocator(Locator locator) //用于处理文档解析开始事件 public void startDocument()throws SAXException //处理元素开始事件,从参数中可以获得元素所在名称空间的uri,元素名称,属性类表等信息 public void startElement(String namespacesURI , String localName , String qName , Attributes atts) throws SAXException //处理元素结束事件,从参数中可以获得元素所在名称空间的uri,元素名称等信息 public void endElement(String namespacesURI , String localName , String qName) throws SAXException //处理元素的字符内容,从参数中可以获得内容 public void characters(char[] ch , int start , int length) throws SAXException
这里再介绍下XMLReader中的方法。
//注册处理XML文档解析事件ContentHandlerpublic void setContentHandler(ContentHandler handler) //开始解析一个XML文档public void parse(InputSorce input) throws SAXException
二、SAX实现解析的步骤:
在android中使用SAX是有迹可循的,完全可以按照下面的方法就可以轻松找到xml里的tag,然后得到想要的内容。具体实现步骤如下:
(一)第一步:新建一个工厂类SAXParserFactory,代码如下:
SAXParserFactory factory = SAXParserFactory.newInstance();
(二)第二步:让工厂类产生一个SAX的解析类SAXParser,代码如下:
SAXParser parser = factory.newSAXParser();
(三)第三步:从SAXPsrser中得到一个XMLReader实例,代码如下:
XMLReader reader = parser.getXMLReader();
---可以不要reader将第五步修改为parser.parse(xmlfile,handler);
(四)第四步:把自己写的handler注册到XMLReader中,一般最重要的就是ContentHandler,代码如下:
RSSHandler handler = new RSSHandler();reader.setContentHandler(handler);
(五)第五步:将一个xml文档或者资源变成一个java可以处理的InputStream流后,解析正式开始,代码如下:
reader.parse(inputstream);
上面几个步骤中,最重要、最关键的就是第四步,handler的实现。
具体如下所示:
SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); XMLReader reader = parser.getXMLReader(); RSSHandler handler = new RSSHandler(); reader.setContentHandler(handler); InputSource is = new InputSource(this.getClassLoader().getResourceAsStream("xmlFile.xml"));//取得本地xml文件 reader.parse(is);
或者:
SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); RSSHandler handler = new RSSHandler();reader.parse(xmlFile,handler);
下面通过一个RSS解析的例子说明handler的实现:
我们先是自己见一个rss的xml文档,实现本地解析,新建的rss文档如下:
<?xml version="1.0" encoding="UTF-8"?> <channel> <title>RSS 解析练习</title> <description>hehehaha</description> <link>http://www.cnblogs.com/felix-hua/</link> <language>zh-cn</language> <item> <title><![CDATA[头条]]></title> <link>http://mc.cz001.com.cn/images/menu/23_active.png</link> <category>0</category> <description>描述详细信息的</description> <pubDate>2012-01-09</pubDate> </item>
建好后,我们命名为rssxml.xml,然后放到项目的根目录下:
下面就是最最重要的地方了,建立自己的ContentHandler.看下面的代码:
RSSHandler.java
package com.sax.org.handler; import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler; import com.sax.org.entity.RSSFeed;import com.sax.org.entity.RSSItem; public class RSSHandler extends DefaultHandler{ String currentTag;
String currentValue;
@Override public void startDocument() throws SAXException { // TODO Auto-generated method stub super.startDocument(); } @Override public void endDocument() throws SAXException { // TODO Auto-generated method stub } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // TODO Auto-generated method stub
currentTag=localName; } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // TODO Auto-generated method stubcurrentTag=localName;}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
currentValue = new String(ch, start, length).trim();//从当前 String 对象移除所有前导空白字符和尾部空白字符。 //操作 }}
开启解析只需要根据上面步骤进行即可。