您的位置:首页 > 移动开发 > Android开发

Android 使用SAX读取XML文件

2013-04-13 15:49 483 查看
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;

}

@Override
protected 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());

}
}

}

@Override
public 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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: