SAX全称simple API for XML,同DOM一样也是一个访问XML文档的接口。SAX并不是一个实际可以直接对XML进行解析的解析器,而是他兼容SAX的解析器要实现的接口帮助类的集合。实现了SAX的解析器有很多,如Apache的Xerces,Oracle的XML Parser等。当然在Android中也支持SAX来解析XML,在Android的jar文件包中可以看到两个和SAX相关的包,它们分别是org.xml.sax和org.xml.sax.helper。
解析XML可以采用DOM进行解析,也可以采用SAX进行解析,SAX的设计事先与DOM是完全不同的。DOM处理XML文档是基于将XML文档解析成树状模型,放入内存中进行处理。而SAX则是采用基于事件驱动的处理模式,它将XML文档转化成一系列的事件,由单独的事件处理器来决定如何处理。当然各有各的好处,根据情况不同,而采用不同的解析方式。
DOM(文件对象模型),为XML文档的解析定义了一组接口。解析器读入整个文档,然后构建一个留驻内存的树结构,然后代码就可以使用DOM接口来操作整个树结构。
优点:整个文档树在内存当中,便于操作,支持删除、修改、重新排列等多种功能。
缺点:将整个文档调入内存,包过大量的无用的节点,延长了时间,过多占用了内存空间。
使用场合:一旦解析了文档还需多次访问这些数据、对硬件方面内存CPU有一定的要求。
为了解决DOM解析引起的的这些问题,出现了SAX。当解析器开始发现元素、解析结束,文本、文档的开始或者结束时,发送事件,我们编写响应这些事件的代码。
优点:不用事先调入整个文档,占用资源少。尤其在嵌入式环境,如Android,极力推荐采用SAX进行解析。
缺点:不像DOM一样将文档树长期留驻在内存,数据不是长久的。事件过后,若没保存数据,那么数据就会丢失。
使用场合:机器有性能限制,尤其是在嵌入式环境。
基于事件的处理模式主要是围绕着事件源以及事件处理器或叫监听器来工作的。一个可以产生时间的对象被称为事件源,而可以针对事件产生相应的对象就被叫做事件处理器。事件源和事件处理器是通过在事件中注册方法链接的。这样当事件源产生后,调用事件处理器相应的处理方法,一个事件就获得了处理。当然在事件源调用事件处理器中特定方法时会传递给事件处理器相应事件状态信息,这样事件处理器才能够根据事件信息来决定自己的行为。
在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parse()方法来开始解析XML文档,并根据文档内容产生事件。而事件处理器则是org.xml.sax包中的ContentHandler,DTDHandler,ErrorHandler,以及EntityResolver这个接口。它们分别处理事件源在解析过程中产生不同种类的事件(其中DTDHandler是为解析文档DTD时而用的)。而事件源XMLReader和这四个事件处理器的连接是通过在XMLReader中的相应事件处理器注册方法set来完成的。最常用的是setContentHandler。
处理器名称: 处理事件: 注册方法:
org.xml.sax.ContentHandler 跟文档相关的所有事件如: XMLReader中setContentHandler(ContentHandler handler)
文档的开始和结束、 元素的开始和结束 、可忽略的实体
名称空间前缀映射开始和结束 、 处理指令、字符数据和空格
org.xml.saxErrorHandler 处理XML文档解析时产生的错误。 setErrorHandler(ErrorHandler handler)
org.xml.sax.DTDHandler 处理对文档DTD进行解析时产生的相应事件 setDTDHandler(DTDHandler handler)
org.xml.sax.EntityResolver 处理外部实体 setEntityResolver(EntityResolver resolver)
ContentHandler接口中的方法说明
方法名 方法说明:
public void setDocumentLocator(Locator locator) 设置一个可以定位文档内容事件发生位置的定位器对象
public void startDocument()throws SAXException 用于处理文档解析开始事件
public void endDocument()throws SAXException 用于处理文档解析结束事件
public void startElement(java.lang.String namespaceURI, 处理元素开始时间,从参数中可以获得元素所在的名称空间的uri,元素名称,属性列表等信息
java.lang.String localName,java.lang.String qName
Attributes atts)throws SAXException
public void endElement(java.lang.String namespaceURI, 处理元素结束事件,从参数中可以获得元素所在名称空间的uri,元素名称等信息
java.lang.String localName,java.lang.String qName)
throws SAXException
public void characters(char[] ch,int start,int length) 处理元素的字符内容,从参数中可以获得内容
throws SAXException
org.xml.sax.XMLReader中的方法
public void setContentHandler(ContentHandler handler) 注册处理XML文档内容解析事件的ContentHandler
public void parse(InputSource input)
throws java.IOException,SAXException 开始解析一个XML文档
由于工作需要用心学习了一下Android系统自带的SAX针对xml的解析方法,参考网上的资料自己写个小例子!
建个项目名为SaxActivity源代码如下:
001 |
package com.sax.demo; |
003 |
import java.io.InputStream; |
004 |
import java.util.ArrayList; |
006 |
import javax.xml.parsers.SAXParser; |
007 |
import javax.xml.parsers.SAXParserFactory; |
009 |
import org.xml.sax.Attributes; |
010 |
import org.xml.sax.InputSource; |
011 |
import org.xml.sax.XMLReader; |
013 |
import android.app.Activity; |
014 |
import android.os.Bundle; |
015 |
import android.sax.Element; |
016 |
import android.sax.EndElementListener; |
017 |
import android.sax.EndTextElementListener; |
018 |
import android.sax.RootElement; |
019 |
import android.sax.StartElementListener; |
020 |
import android.util.Log; |
021 |
import android.widget.TextView; |
024 |
* @author Administrator |
025 |
*@description 使用android系统自带的sax包进行XML解析 |
027 |
public class SaxActivity extends Activity { |
028 |
private String result = "会员信息:\n" ; |
029 |
private ArrayList<Person> PersonList = new ArrayList<Person>(); |
030 |
private Person person = null ; |
031 |
public void onCreate(Bundle savedInstanceState) { |
032 |
super .onCreate(savedInstanceState); |
033 |
setContentView(R.layout.main); |
036 |
InputStream inputStream = this .getClassLoader().getResourceAsStream( "PersonDetail.xml" ); |
037 |
SAXParserFactory factory = SAXParserFactory.newInstance(); |
038 |
SAXParser parser = factory.newSAXParser(); |
039 |
XMLReader reader = parser.getXMLReader(); |
040 |
reader.setContentHandler(getRootElement().getContentHandler()); |
041 |
reader.parse( new InputSource(inputStream)); |
043 |
} catch (Exception e) { |
046 |
for (Person person:PersonList){ |
047 |
result += person.toString() + "\n" ; |
049 |
TextView textView = (TextView)findViewById(R.id.textView); |
050 |
textView.setText(result); |
054 |
* @return 返回设置好处理机制的rootElement |
056 |
private RootElement getRootElement(){ |
057 |
/*rootElement代表着根节点,参数为根节点的TAGName*/ |
058 |
RootElement rootElement = new RootElement("PersonDetail"); |
060 |
* 这里需要注意,虽然我们只设置了一次person的事件,但是我们文档中根节点下的所有 |
063 |
Element personElement = rootElement.getChild( "person" ); |
064 |
// 读到元素开始位置时触发,如读到<person>时 |
065 |
personElement.setStartElementListener( new StartElementListener() { |
067 |
public void start(Attributes attributes) { |
068 |
// TODO Auto-generated method stub |
069 |
Log.i( "通知" , "start" ); |
070 |
person = new Person(); |
073 |
//读到元素结束位置时触发,如读到</person>时 |
074 |
personElement.setEndElementListener( new EndElementListener() { |
077 |
PersonList.add(person); |
081 |
Element nameElement = personElement.getChild( "name" ); |
082 |
// 读到文本的末尾时触发,这里的vip即为文本的内容部分 |
083 |
nameElement.setEndTextElementListener( new EndTextElementListener() { |
085 |
public void end(String vip) { |
090 |
Element ageElement = personElement.getChild( "age" ); |
091 |
ageElement.setEndTextElementListener( new EndTextElementListener() { |
093 |
public void end(String vip) { |
097 |
Element jobElement = personElement.getChild( "job" ); |
098 |
jobElement.setEndTextElementListener( new EndTextElementListener() { |
100 |
public void end(String vip) { |
106 |
private class Person { |
110 |
public String getName() { |
113 |
public void setName(String name) { |
116 |
public String getAge() { |
119 |
public void setAge(String age) { |
122 |
public String getJob() { |
125 |
public void setJob(String job) { |
129 |
public String toString() { |
130 |
return "会员详细资料:年龄=" + age + ", 姓名=" + name + ", 工作=" + job + " " ; |
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/textView" android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
PersonDetail.xml文件存在src文件夹中代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<PersonDetail>
<person>
<name>李明</name>
<age>25</age>
<job>业务员</job>
</person>
<person>
<name>刘洋</name>
<age>34</age>
<job>医生</job>
</person>
</PersonDetail>
运行效果如图