相信各位android开发者,对SAX已经并不陌生了,SAX(Simple API for XML),是一个使用非常广泛的XML解析标准,通常使用Handler模式来处理XML文档,这种处理模式和我们平常习惯的理解方式很不同,身边也经常有一些朋友在刚接触SAX的时候会觉得理解起来有些困难。其实SAX并不复杂,只不过是换了一种思维方式,正如它的名字所表示的,为了让我们以更简单的方式来处理XML文档,下面我们就开始吧。
我们通常的理解方式是,我们给出一个输入(比如xml文档的地址),然后程序返回给我们数据(比如解析后的xml文档结构),我们在返回给我们的结果中进行相应的操作,而SAX以一种更简单的方式来处理XML文档的解析,也就是处理器模式,一个使用SAX的简单示例:
- SAXParserFactory spf = SAXParserFactory.newInstance();
- SAXParser sp = spf.newSAXParser();
- XMLReader reader = sp.getXMLReader();
- reader.setContentHandler(myHandler);
- reader.parse(new InputSource(new URL(url).openStream()));
下面我们来详细介绍一下处理器,SAX处理器使用的是一种和我们平时的理解方式不太一样的处理形式,是在遍历文档的同时,让我们来进行文档的处理。
用一个实际的例子来解释更为方便,假如有下面这样一个XML文档:
- <student>
- <name>张三</name>
- <age>22</age>
- <sn>1001</sn>
- </student>
- <student>
- <name>李四</name>
- <age>21</age>
- <sn>1002</sn>
- </student>
- public class MyHandler extends DefaultHandler {
- public void startElement(String uri, String localName, String qName,
- }
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- }
- public void characters(char[] ch, int start, int length)
- throws SAXException {
- }
- }
endElement方法,在结束一个节点的时候会调用,例如进入到</student>节点时,该方法会被调用。
characters方法,在进入XML节点的文本节点(TextNode)时会被调用,例如<name>张三</name>,在便利到‘张三’这个文本节点的时候,这个方法会被调用。
另外还有两个回调方法,分别为startDocument,endDocument,顾名思义,这两个方法为进入文档和离开文档时要调用的方法。
下面我们就来自己写一个处理器来解析上面的XML文档。首先我们需要将每个节点封装成一个实体对象:
- public class Student {
- private String name;
- private int age;
- private String sn;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getSn() {
- return sn;
- }
- public void setSn(String sn) {
- this.sn = sn;
- }
- }
- public class MyHandler extends DefaultHandler {
- private List<Student> studentList;
- private boolean inStudent = false;
- private boolean studentName = false;
- private boolean studentAge = false;
- private boolean studentSN = false;
- private Student curStudent ;
- public MyHandler() {
- studentList = new ArrayList<Student>();
- }
- @Override
- public void startElement(String uri, String localName, String qName,
- Attributes attributes) throws SAXException {
- String tagName = localName.length() != 0 ? localName : qName;
- tagName = tagName.toLowerCase().trim();
- if(tagName.equals("student")) {
- inStudent = true;
- curStudent = new Student();
- }
- if(inStudent) {
- if(tagName.equals("name")) {
- studentName = true;
- }else if(tagName.equals("age")) {
- studentAge = true;
- }else if(tagName.equals("sn")) {
- studentSN = true;
- }
- }
- }
- @Override
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- String tagName = localName.length() != 0 ? localName : qName;
- tagName = tagName.toLowerCase().trim();
- if(tagName.equals("student")) {
- inStudent = true;
- studentList.add(curStudent);
- }
- if(inStudent) {
- if(tagName.equals("name")) {
- studentName = false;
- }else if(tagName.equals("age")) {
- studentAge = false;
- }else if(tagName.equals("sn")) {
- studentSN = false;
- }
- }
- }
- @Override
- public void characters(char[] ch, int start, int length)
- throws SAXException {
- if(studentName) {
- curStudent.setName(curStudent.getName() + new String(ch,start,length));
- }else if (studentAge) {
- curStudent.setAge(Integer.parseInt(new String(ch,start,length)));
- }else if(studentSN) {
- curStudent.setSn(curStudent.getSn() + new String(ch, start, length));
- }
- }
- }
注意到,这里curStudent.setName(curStudent.getName() + new String(ch,start,length)),我们用以前的值和新的值连接起来,而不是直接设置curStudent.setName(new String(ch,start,length))。这是因为在遍历<name>.....</name>这中间的文本节点的时候,有些时候这对标签中的内容可能会被看做多个文本节点,比如包含Html实体的情况下 <name>张 三</name>,这里相当于包含了两个文本节点,如果不使用连接的方式而采用直接设置的方式,那么我们最终只能得到最后一次设置的值,因为前面设置的被覆盖了。那么我们最终取得到的名字就是‘三’了。
这个处理器的核心分功能就算完成了,下面我们还需要增加一个方法,用来返回处理后的内容:
- public List<Student> getStudentList() {
- return studentList;
- }
- SAXParserFactory spf = SAXParserFactory.newInstance();
- SAXParser sp = spf.newSAXParser();
- XMLReader reader = sp.getXMLReader();
- List<Student> list;
- reader.setContentHandler(myHandler);
- reader.parse(new InputSource(new URL(url).openStream()));
- list = myHandler.getStudentList();
最后总结一下,SAX并不复杂,只要理解了它的思维方式,我们就可以游刃有余,使它成为我们开发的利器,这篇文章向大家介绍了SAX的一些基本知识,希望能起到一个抛砖引玉的作用,大家能够使用它来创造出更多好的应用,当然可能有一些地方解释的还不是十分完美,如果有一些不好理解的地方,还望大家指出。
![](http://www.1000phone.net/static/image/smiley/default/lol.gif)
另外下面是SAX的一个官方网站,里面有一些介绍和代码示例,英文不错的童鞋可以来这里参考一下
![](http://www.1000phone.net/static/image/smiley/default/loveliness.gif)
http://www.saxproject.org/