代码改变世界

Android解析XML之SAX解析器

2015-04-24 21:29  肖恩也有梦想  阅读(431)  评论(0编辑  收藏  举报

SAX(Simple API for XML)解析器是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。

SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。

SAX相关类及API

DefaultHandler:是一个事件处理器,可以接收解析器报告的所有事件,处理所发现的数据。它实现了EntityResolver接口、DTDHandler接口、ErrorHandler接口和ContentHandler接口。这几个接口代表不同类型的事件处理器。

利用SAX解析XML,实际上只需要继承DefaultHandler类,然后重写几个关键性方法即可。一般我们需要重写的方法是startDocument、startElement、characters、endElement和endDocument方法。

API解释:

 1 import org.xml.sax.Attributes;
 2 import org.xml.sax.SAXException;
 3 import org.xml.sax.helpers.DefaultHandler;
 4 
 5 public class MyParser extends DefaultHandler{
 6     
 7     /**
 8      * 当文档开始解析时此函数被调用
 9      * 
10      * 通常我们需要在这里面做一些初始化的工作,比如分配某些资源
11      */
12     @Override
13     public void startDocument() throws SAXException {
14         super.startDocument();
15     }
16     
17     /**
18      *  当扫描到文档元素节点起始标志时被调用
19      *  
20      *  通常我们需要做一下标记,或者分配节点资源。
21      */
22     @Override
23     public void startElement(String uri, String localName, String qName,
24             Attributes attributes) throws SAXException {
25         super.startElement(uri, localName, qName, attributes);
26     }
27     
28     /**
29      *  扫描到元素节点中的字符串内容时调用此函数
30      *  @param ch  代表元素内容的字符数组(实测时候并不完全表示元素内容,不过这不影响)
31      *  @param start 能够使用的起始位置
32      *  @param length 能够使用的数组长度
33      */
34     @Override
35     public void characters(char[] ch, int start, int length)
36             throws SAXException {
37         super.characters(ch, start, length);
38     }
39     
40     
41     /**
42      * 扫描到元素节点结束标志时调用
43      * 
44      * 应该是最重要的一个方法。需要判断节点名作相应的数据解析。
45      * @param localName  节点名字
46      * @param qName 含限定符的节点名字
47      */
48     @Override
49     public void endElement(String uri, String localName, String qName)
50             throws SAXException {
51         super.endElement(uri, localName, qName);
52     }
53     
54     /**
55      * 扫描文档结束后调用
56      * 
57      *  如果有些资源需要释放的话,就在这里做好了。
58      */
59     @Override
60     public void endDocument() throws SAXException {
61         super.endDocument();
62     }
63     
64 }
API解释

实例

需要解析的persons.xml文件内容如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <persons>
 3     <person id="1" group="1">
 4         <name>张三</name>
 5         <age>24</age>
 6     </person>
 7     <person id="2" group="2">
 8         <name>李四</name>
 9         <age>25</age>
10     </person>
11     <person id="3" group="1">
12         <name>王五</name>
13         <age>26</age>
14     </person>
15 </persons>

定义Person实体类:

/**
 * Created by Shane on 2015/4/24.
 */
public class Person {
    private int id;
    private int group;
    private String name;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getGroup() {
        return group;
    }

    public void setGroup(int group) {
        this.group = group;
    }

    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;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();

        sb.append("name: " + name);
        sb.append(", age: " + age);
        sb.append(", id: " + id);
        sb.append(", group: " + group);

        return sb.toString();
    }
}
Person.java

 

定义用于解析XML文件的解析器PersonSAXHandler 类如下:

/**
 * Created by Shane on 2015/4/24.
 */
public class PersonSAXHandler extends DefaultHandler{

    private static final String TAG_PERSON = "person";
    private static final String TAG_NAME = "name";
    private static final String TAG_AGE = "age";

    private List<Person> persons;
    private Person person;

    private StringBuffer stringBuffer;

    public List<Person> getPersons() {
        return persons;
    }

    @Override
    public void startDocument() throws SAXException {
        super.startDocument();

        persons = new ArrayList<>();
        stringBuffer = new StringBuffer();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);

        if (localName.equals(TAG_PERSON)) {
            person = new Person();
            person.setId(Integer.parseInt(attributes.getValue(0)));
            person.setGroup(Integer.parseInt(attributes.getValue(1)));
        }
        stringBuffer.setLength(0);  // start a new string buffer.
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);

        stringBuffer.append(ch, start, length);
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);

        if (localName.equals(TAG_PERSON)) {
            persons.add(person);
        } else if (localName.equals(TAG_NAME)) {
            person.setName(stringBuffer.toString().trim());
        } else if (localName.equals(TAG_AGE)) {
            person.setAge(Integer.parseInt(stringBuffer.toString().trim()));
        }

    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }
}

 

包装上述PersonSAXHandler类,定义PersonSAXParser类进行解析:

/**
 * Created by Shane on 2015/4/24.
 */
public class PersonSAXParser implements PersonParser{

    @Override
    public List<Person> parse(InputStream inputStream) {
        List<Person> persons = new ArrayList<>();
        try {
            SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
            PersonSAXHandler personSAXHandler = new PersonSAXHandler();
            saxParser.parse(inputStream, personSAXHandler);
            persons = personSAXHandler.getPersons();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {}
            }
        }
        return persons;
    }
}

PersonParser接口定义如下:

/**
 * Created by Shane on 2015/4/24.
 */
public interface PersonParser {
public List<Person> parse(InputStream inputStream);
}