Android 使用SAX读取XML文件

来源:互联网 发布:有关柳叶图形算法 编辑:程序博客网 时间:2024/06/05 10:57
SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于Android等移动设备。关于它的详细介绍请参考http://www.saxproject.org/

 SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。

下面是一些ContentHandler接口常用的方法:

  • startDocument()  当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理的工作。
  • endDocument()    和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。 
  • startElement(String namespaceURI, String localName, String qName, Attributes atts)    当读到一个开始标签的时候,会触发这个方法。namespaceURI就是命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名。通过atts可以得到所有的属性名和相应的值。要注意的是SAX中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会纪录下以前所碰到的标签,也就是说,在startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元属等等其它与结构相关的信息,都是不得而知的,都需要你的程序来完成。这使得SAX在编程处理上没有DOM来得那么方便。
  • endElement(String uri, String localName, String name)   这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。
  • characters(char[] ch, int start, int length)    这个方法用来处理在XML文件中读到的内容,第一个参数用于存放文件的内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。
假设我们要解析的xml文件内容如下:

<?xml version="1.0" encoding="UTF-8"?><persons><person id="23"><name>李明</name><age>30</age></person><person id="20"><name>李向梅</name><age>25</age></person></persons>


解析itcast.xml触发的事件为:

读到的标签及内容       触发事件 

{文档开始}          startDocument() 

<persons>           startElement(, "persons", null, "{Attributes}")

"\n\t"              characters("<persons>...</persons>", "12", "2")

<person>            startElement(, "person", null, "{Attributes}")

"\n\t\t"            characters("<persons>...</persons>", "31", "3")

<name>              startElement(, "name", null, "{Attributes}")

"李明"              characters("<persons>...</persons>", "40", "2")

</name>             endElement("", "name", null)

"\n\t\t"            characters("<persons>...</persons>", "50", "3")

<age>               startElement(, "age", null, "{Attributes}")

"30"                characters("<persons>...</persons>", "58", "2")

</age>              endElement("", "age", null)

"\n\t"              characters("<persons>...</persons>", "67", "2")

</person>           endElement("", "person", null)

"\n\t"              characters("<persons>...</persons>", "79", "2")

<person>            startElement(, "person", null, "{Attributes}")

"\n\t\t"            characters("<persons>...</persons>", "98", "3")

<name>              startElement(, "name", null, "{Attributes}")

"李向梅"            characters("<persons>...</persons>", "107", "3")

</name>             endElement("", "name", null)

"\n\t\t"            characters("<persons>...</persons>", "118", "3")

<age>               startElement(, "age", null, "{Attributes}")

"25"                characters("<persons>...</persons>", "126", "2")

</age>              endElement("", "age", null)

"\n\t"              characters("<persons>...</persons>", "135", "2")

</person>           endElement("", "person", null)

"\n"                characters("<persons>...</persons>", "147", "1")

</persons>          endElement("", "persons", null)

{文档结束}          endDocument() 

下面我们给出一个读取xml文件的实例:
首先新建一个person类,用来存放xml结构的数据
person.java
package com.example.xmlparsedemo;public class Person {private Integer id;private String name;private Short age;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Short getAge() {return age;}public void setAge(Short age) {this.age = age;}}

然后继承ContentHandler,并重载用到的函数:
XMLContentHandler.java
package com.example.xmlparsedemo;import java.util.ArrayList;import java.util.List; import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;public class XMLContentHandler extends DefaultHandler { private List<Person> persons = null;private Person currentPerson;private String tagName = null;//当前解析的元素标签public List<Person> getPersons() {return persons;}/** 接收文档的开始的通知。*/@Override public void startDocument() throws SAXException {persons = new ArrayList<Person>();}/** 接收字符数据的通知。*/@Override public void characters(char[] ch, int start, int length) throws SAXException {   if(tagName!=null){   String data = new String(ch, start, length);   if(tagName.equals("name")){this.currentPerson.setName(data);   }else if(tagName.equals("age")){this.currentPerson.setAge(Short.parseShort(data));   }  }}/** 接收元素开始的通知。* 参数意义如下:*    namespaceURI:元素的命名空间*    localName :元素的本地名称(不带前缀)*    qName :元素的限定名(带前缀)*    atts :元素的属性集合*/@Override public void startElement(String uri, String localName, String qName,Attributes attributes)throws SAXException {if(localName.equals("person")){currentPerson = new Person();currentPerson.setId(Integer.parseInt(attributes.getValue("id")));}this.tagName = localName;}/** 接收文档的结尾的通知。* 参数意义如下:*    uri :元素的命名空间*    localName :元素的本地名称(不带前缀)*    name :元素的限定名(带前缀)* */@Override public void endElement(String uri, String localName, String name) throws SAXException {if(localName.equals("person")){persons.add(currentPerson);currentPerson = null;}this.tagName = null;}}

然后在mianAcitvity里添加一个解析xml的API readXml

public static List<Person> readXML(InputStream inStream) {   try {SAXParserFactory spf = SAXParserFactory.newInstance();SAXParser saxParser = spf.newSAXParser(); //创建解析器//设置解析器的相关特性,http://xml.org/sax/features/namespaces = true 表示开启命名空间特性  //saxParser.setProperty("http://xml.org/sax/features/namespaces",true);XMLContentHandler handler = new XMLContentHandler();saxParser.parse(inStream, handler);inStream.close();return handler.getPersons();   } catch (Exception e) {   e.printStackTrace();   }  return null;}
}
最终须有在mainAcitvity里测试该接口能否完成任务:
MainActivity.java
package com.example.xmlparsedemo;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.InputStream;import java.net.URL;import java.util.List;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import android.os.Bundle;import android.app.Activity;import android.util.Log;import android.view.Menu;public class MainActivity extends Activity {private List<Person> persons = null;private Person p=null;public static List<Person> readXML(InputStream inStream) {try {SAXParserFactory spf = SAXParserFactory.newInstance();SAXParser saxParser = spf.newSAXParser(); //创建解析器//设置解析器的相关特性,http://xml.org/sax/features/namespaces = true 表示开启命名空间特性  //saxParser.setProperty("http://xml.org/sax/features/namespaces",true);XMLContentHandler handler = new XMLContentHandler();saxParser.parse(inStream, handler);inStream.close();return handler.getPersons();} catch (Exception e) {   e.printStackTrace();   }return null;}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);InputStream r =null;r=  getClass().getResourceAsStream("test.xml");if (r==null){Log.v("com.example.exlparsedemo", "file not found");return;}URL url = getClass().getResource("test.xml");String path= url.getPath();persons=readXML(r);if(null!=persons){for(int i=0;i<persons.size();i++){p=persons.get(i);Log.v("id", p.getId().toString());Log.v("name", p.getName());Log.v("age", p.getAge().toString());}}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.activity_main, menu);return true;}}


至此,基本完成使用SAX解析xml的完整例子。
该demo运行的结果是可以从log中看到 xml里保存的两个person 的in、name、 age。