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事件確定會返回整個事件的內容"
相關文章
相關標籤/搜索