在JAVA中有两种常见的XML解析方式,DOM和SAX,DOM在解析的时候会将所有的数据一次性载入内存中进行解析,在数据量比较大的情况下,效率非常低.尤其在手机这种对内存和性能要求比较苛刻的设备里面这种方法并不可取.
android里面可以使用SAX进行解析.SAX是基于事件驱动的。在用SAX解析xml文档时候,在读取到文档开始和结束标签时候就会回调一个事件,在读取到其他节点与内容时候也会回调一个事件。在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法来解析XML文档,并产生事件。事件处理器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口.ContentHander用于处理跟XML文档相关的事件,DTDHander用于处理对文档的DTD进行解析时产生的事件,ErrorHandler用于处理XML文档产生的错误,EntityResolver用于处理外部实体.值得注意的是,在使用ContentHandler时,他在这个包下:org.xml.sax.*而通常我们在解析XML时会与网络发生交互,常常会导入以下这个包:
import java.net.*;
在这个包下面也有一个ContentHandler,这样会发生错误.
更为方便的是android SDK中提供了DefaultHandler和DefaultHandler2 来协助我们完成构建XML handler,事实上DefaultHandler本身实现了 ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口,相当于把这几个接口做了一次集成,而DefaultHandler2继承自DefaultHandler,可以用来处理更加丰富的事件.我们常常使用DefaultHandler来作为事件处理handler.常用的处理过程如下:
1:创建一个SAXParserFactory对象
2: 根据SAXParserFactory.newSAXParser()方法返回一个SAXParser解析器
3:根据SAXParser解析器获取事件源对象XMLReader
4:实例化一个DefaultHandler对象
5:连接事件源对象XMLReader到事件处理类DefaultHandler中
6:调用XMLReader的parse方法从输入源中获取到的xml数据
7:通过DefaultHandler返回我们需要的数据集合。
接下来以一个小例子来介绍这种解析方式:
首先在assets目录下创建一个名为min的XML文件
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id="0">
<name>min</name>
<age>30</age>
</person>
<person id="1">
<name>malone</name>
<age>25</age>
</person>
</persons>
创建一个类public class MinHandler extends DefaultHandler ,里面定义三个私有数据成员:
private List<Person> persons;
private Person person;
private String preTag;
一个内部类Person,包含三个数据成员:
private String name;
private int age;
private Integer id;
生成其set和get方法.
重写以下方法:
@Override
public void startDocument() throws SAXException {
persons = new ArrayList<Person>();
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if(person!=null){
String data = new String(ch,start,length);
if("name".equals(preTag)){
person.setName(data);
}else if ("age".equals(preTag)){
person.setAge(new Short(data));
}
}
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if("person".equals(localName)){
person = new Person();
person.setId(new Integer(attributes.getValue("", "id")));
}
preTag = localName;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("person".equals(localName)&&person!=null){
persons.add(person);
person = null;
}
preTag = null;
}
最后定义一个外部接口,获取解析后的数据:
public List<Person> getPersons() {
return persons;
}
接下来在我们的Activity中实现解析:
定义两个全局变量:
XMLReader xmlReader;
MinHandler mMinHandler = new MinHandler();
创建工厂类 SAXParserFactory s = SAXParserFactory.newInstance();
获取XMLReader :
try {
xmlReader = s.newSAXParser().getXMLReader();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
设置handler xmlReader.setContentHandler(mMinHandler);
开始解析:
try {
InputSource input = new InputSource(getAssets().open("min.xml"));
xmlReader.parse(input);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
查看解析结果:
List<Person> l = mMinHandler.getPersons();
for(int i=0;i<l.size();i++) {
Person p = l.get(i);
Log.d("minrui","p.getAge() = "+p.getAge());
Log.d("minrui","p.getId() = "+p.getId());
Log.d("minrui","p.getName() = "+p.getName());
}
结果打印如下:
01-01 09:30:41.152: DEBUG/minrui(3421): p.getAge() = 30
01-01 09:30:41.152: DEBUG/minrui(3421): p.getId() = 0
01-01 09:30:41.152: DEBUG/minrui(3421): p.getName() = min
01-01 09:30:41.152: DEBUG/minrui(3421): p.getAge() = 25
01-01 09:30:41.152: DEBUG/minrui(3421): p.getId() = 1
01-01 09:30:41.152: DEBUG/minrui(3421): p.getName() = malone
就这样实现了一个简单的sax解析器,有以下不足之处,解析过程中如果发生错误,就不能再解析下去了.针对不同的XML需要写不同的解析器,没有一个通用的模板.