Android常見三種XML解析方式(SAX,PULL,DOM)
環境搭建:
首先我們需要一個測試用的XML文檔,以及搭建本地服務器,這里使用的是Tomcat,來模仿手機從網絡上獲取xml文檔的環境
在搭建好本地服務器以及部署文檔后,我們開始在代碼中啟動線程去訪問這個xml文檔,在 Android模擬器中 localhost 的IP地址是 10.0.2.2, 代碼如下:
在 connection 調用 conncet 方法后 使用 getResponseCode 方法返回連接的狀態,200的意思代表OK,我們常見的404 Not Found也是此類狀態碼(status code),接著獲取連接的輸入流 inputStream,我們的XML解析就從這個輸入流開始
SAX解析:
SAX解析XML需要用到一個 org.xml.sax.helpers 包下的 DefaultHandler 類,我們需要自己創建一個類繼承于 DefaultHandler ,實現其中我們需要的幾個方法, 我們先來看代碼:
我們從 SAXParserFactory 工廠方法中獲取到 XMLReader 的實例,再實例化我們自己創建,繼承于 DefaultHandler 的 SAXParseHandler 類,最后設置 reader 的Handler為我們自己創建的類,設置 reader 的解析的數據來源,接下來我們來看 SAX 解析 XML文檔的過程。
SAX解析XML的過程就在我們創建的類 SAXParseHandler 中, 先上代碼:
代碼中重寫的五個方法從字面意思可以知道大致的作用,我們在代碼中加入相應的 Log 調試輸出語句,來看看SAX解析XML的過程。
結合我們的XML文檔,可以看出SAX解析XML時,首先會回調 startDocument() 方法,結束整個文檔的解析時會調用 endDocument() 方法,當遇到標簽元素時,會調用 startElement()方法,這里我們打印出了此時解析的 nodeName,就是我們XML文檔中的第一個標簽元素 <apps> ,接著會調用 characters 方法,顯示長度 length 為 1 ,輸出內容還換行了,這是因為 <apps> 標簽后面有一個換行符,接下來繼續調用 characters 方法,是因為下一個元素標簽 <app> 前面有四個空格符,length就是4。總結的規律就是遇到 <app><id> 此類標簽時就會調用 startElement()方法,</app></id>此類標簽時就調用 endElement()方法,遇到其他內容就會調用 characters 方法,摸清解析過程后,我們來獲取 XML文檔中我們想要的數據。
開始解析
在 startDocument() 方法中初始化我們的三個 StringBuilder 來存儲接著我們要獲取的數據,接著在 startElement 方法中記錄下 此時的 nodeName,也就是<id>還是<name>此類標簽
我們知道一般在調用 startElement 方法后,比如解析到<id>標簽后,nodeName值為 id ,就會調用 characters 方法獲取 <id> 標簽后的內容,代碼通過 switch 以 nodeName 為條件,假如之前 startElement 方法 nodeName為 id,相應的就把接下來的 characters 方法獲取的內容 append 到我們創建的對應 id 的 StringBuilder中。
最后在 endElement 方法中,如果 localName為 <app>,代表我們 app 標簽里面的 <id> <name> <version> 已經解析完畢,將其打印出來,因為 characters 方法會把各種換行符也讀取出來,所以這里用 trim 方法整理下內容,接著清空 StringBuilder ,進入下一個 <app></app>標簽循環,直到文檔全部解析完畢。
SAX解析XML大致過程就是這樣,簡單粗暴,代碼邏輯也較為清晰,但一旦開始解析就會從頭解析到尾,不能直接控制解析的步驟。
PULL解析:
PULL解析是Android官方推薦的XML解析方式,以事件驅動來解析XML,同樣非常好用,先來看看接口 XmlPullParser 里面有哪些事件
從字面意思就可以看出代表什么事件,那怎么用呢, 直接上代碼:
從 XmlPullParserFactory 類中得到 XmlPullParser 實例,通過setInput方法設置要解析的XML 輸入流,getEventType方法返回當前解析XML文檔的事件,在while循環中只要 eventType 不是 END_DOCUMENT就繼續解析XML文檔,通過 parser的 next() 方法獲取下一個事件,這里我們同樣用Log來看一下事件的變化。
EventType后面相應的數字和我們上面接口定義的事件的值是相匹配的,從日志可以看出,事件從 0 START_DOCUMENT 開始,接著是 START_TAG 和 TEXT 交錯,對應 標簽 和 標簽后的內容,這里解析到</app> 標簽才出現 END_TAG 事件,之前的</id> </name> 這些結束標簽確沒有響應 END_TAG 事件,這里搞不懂,但并不影響我們獲取需要的數據。
通過 parser.getName() 方法獲取 nodeName(當前標簽的字符串),后面通過 switch(eventType) 當遇到 START_TAG 事件時判斷此時的 nodeName 是否為我們需要的 id name version,如果是就獲取該標簽內的內容,當遇到 END_TAG 事件,判斷 nodeName 是否為 app,如果是就打印出我們獲取的數據。
PULL方式非常簡潔方便,靈活,我們獲取所需數據后若不用再解析可以很方便的停止解析,PULL是幾種方式中優點最多的,Android官方也推薦此方法來解析XML。
DOM解析:
DOM解析是這幾種方式中最復雜的一個,采用樹形結構來管理XML文檔,同時內存占用也較多,不推薦使用此方法,尤其是在大一點的XML文檔中,但可以學習怎么用, 我直接通過代碼里的注釋來解釋該方式:
是不是看起來有點繞,有點暈,實操之后還是可以理解的,通過不斷的歸納以及細分標簽的內容,最后獲取所需的數據。
總結:
通過對三種解析XML的方式實踐練習后,發現SAX和PULL兩種方式較為好用,PULL更佳。
來自:http://www.jianshu.com/p/2fc35b926e73