android-XML解析之pull类型代码解析

    因为以前的项目使用过xml文件的解析,可是在使用的时候都是从网上找到的代码,稍做修改就使用了,然而对其中的原理并不知因此然,因此再次想使用的时候,感受仍是空空的,不知道如何下手,为了更加深刻的理解xml文件的解析,我从代码实现的角度作一些理解,可是我在看代码的时候,有些代码的实现仍是没有办法读懂,仍是太深奥。下面我就以我之见,写一些东西,做为记录。 html

    在android中XML的解析有三种,分别为:SAX(Simple API XML)、DOM(document object model)、以及今天咱们要说的PULL类型,也是android官方提倡的使用方式。 java

    在讲以前,我先写出通常的使用方式,好比解析如下的XML文档: android


<?xml version="1.0" encoding="UTF-8"?>
<students>
   <student id="1">
      <name>cc</name>
      <age>10</age>
      <grade>100</grade>
   </student>
   <student id="2">
      <name>cy</name>
      <age>11</age>
      <grade>89</grade>
   <student>
</students>

通常的解析手段,java逻辑代码以下(代码截取与网络): 网络

public class TestPullXml {
    public List<Person> getPersons(InputStream instream) throws Exception {
        List<Person> persons = null;
        Person person = null;
        XmlPullParser parser = Xml.newPullParser();//获得Pull解析器
        parser.setInput(instream, "UTF-8");//设置下输入流的编码
        int eventType = parser.getEventType();//获得第一个事件类型
        while (eventType != XmlPullParser.END_DOCUMENT) {
            //若是事件类型不是文档结束的话则不断处理事件
            switch (eventType) {
                case XmlPullParser.START_DOCUMENT://若是是文档开始事件
                    persons = new ArrayList<Person>();建立一个person集合
                    break;
                case (XmlPullParser.START_TAG)://若是遇到标签开始
                    String tagName = parser.getName();// 得到解析器当前元素的名称
                    if ("person".equals(tagName)) {//若是当前标签名称是   
                        <person> person = new Person();//建立一个person
                        //将元素的属性值赋值给id
                        person.setId(new Integer(parser.getAttributeValue(0)));
                    }
                    if (person != null) {//若是person已经建立完成
                        if ("name".equals(tagName))//若是当前节点标记是name
                            person.setName(new String(parser.nextText()));
                        else if ("age".equals(tagName))//若是当前元素节点标记是age
                            person.setAge(new Short(parser.nextText()));
                    }
                    break;
                case (XmlPullParser.END_TAG)://若是遇到标签结束
                    if ("person".equals(parser.getName())) {//若是是person标签结束
                        persons.add(person);//将建立完成的person加入集合
                        person = null;//而且置空
                    }
                    break;
            }
            eventType=parser.next();//进入下一个事件处理
        }
        return persons;
    }

下面,咱们对上述代码,进行分行理解: 函数


XmlPullParser parser = Xml.newPullParser();//获得Pull解析器
首先找到Xml类下的newPullParser方法:



/**
  * Returns a new pull parser with namespace support.
  */
    public static XmlPullParser newPullParser() {
        try {
            KXmlParser parser = new KXmlParser();
            parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
            return parser;
        } catch (XmlPullParserException e) {
            throw new AssertionError();
        }
    }

经过上面的代码,咱们能够发现,实际上该函数返回了一个实现了XmlPullParser接口的类KXmlParser,而且给该对象设置了命名空间和文档声明,因此,对之后的parser对象,咱们所须要分析的实现代码,就要找KXmlParser这个类了。 this

parser.setInput(instream, "UTF-8");//设置下输入流的编码
这一步,咱们先查看一下,官方文档是怎么解释了:


Set the input source for parser to the given reader and resets the parser. The event type is set to the initial value START_DOCUMENT. Setting the reader to null will just stop parsing and reset parser state, allowing the parser to free internal resources such as parsing buffers.



相信你们能够理解这个方法的做用,可是咱们仍是看看它的实现代码吧:


//  public part starts here...

    public void setInput(Reader reader) throws XmlPullParserException {
        this.reader = reader;
        line = 1;
        column = 0;
        type = START_DOCUMENT;
        name = null;
        namespace = null;
        degenerated = false;
        attributeCount = -1;
        encoding = null;
        version = null;
        standalone = null;

        if (reader == null)
            return;

        srcPos = 0;
        srcCount = 0;
        peekCount = 0;
        depth = 0;

        entityMap = new Hashtable<String, String>();
        entityMap.put("amp", "&");
        entityMap.put("apos", "'");
        entityMap.put("gt", ">");
        entityMap.put("lt", "<");
        entityMap.put("quot", "\"");
    }

在这个方法中,初始化了不少在读取XML过程当中须要使用的成员变量,好比type,初始化为START_DOCUMENT,输入流instream,这些都是解析时所必不可少的成员,因此在一开始,必定要调用该方法。设置输入源。 编码


int eventType = parser.getEventType();//获得第一个事件类型



首先咱们要知道,XML的几种事件类型:


START_DOCUMENT、START_TAG、TEXT、END_TAG、END_DOCUMENT

 而后,咱们看下面的一句代码: spa

int eventType = parser.getEventType();//获得第一个事件类型
其实,这句咱们很明显就知道,返回必定是START_DOCUMENT,由于在上一句,setInput()函数中,初始化了type类型为START_DOCUMENT。

在下面的while循环中就是根据这五种事件类型不一样的解析数据,很简单。这里很少说了。 翻译

下面有一句: code

eventType=parser.next();//进入下一个事件处理
也就是这个next函数。

看看官方的文档:

Get next parsing event - element content will be coalesced and only one TEXT event
must be returned for whole element content (comments and processing instructions 
will be ignored and emtity references must be expanded or exception mus be thrown 
if entity reerence can not be exapnded). If element content is empty (content is ""
) then no TEXT event will be reported.
翻译:"获得下一个解析事件,元素的内容将会被合并而且一个TEXT事件确定会返回整个事件的内容"
相关文章
相关标签/搜索