android解析xml文件的方式(其二)

上一節中,咱們使用DOM方式解析xml文檔,該方式比較符合咱們平常思惟方式,容易上手,可是它直接把文檔調入內存中,比較耗內存。在這裏咱們能夠用另一種方式解析xml,這個就是SAX方式。 android

SAX便是:Simple API for XML 函數

SAX是基於事件驅動的。固然android的事件機制是基於回調函數的,在用SAX解析xml文檔時候,在讀取到文檔開始和結束標籤時候就會回調一個事件,在讀取到其餘節點與內容時候也會回調一個事件。 this

既然涉及到事件,就有事件源,事件處理器。在SAX接口中,事件源是org.xml.sax包中的XMLReader,它經過parser()方法來解析XML文檔,併產生事件。事件處理器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以及EntityResolver這4個接口 url

XMLReader經過相應事件處理器註冊方法setXXXX()來完成的與ContentHander、DTDHander、ErrorHandler,以及EntityResolver這4個接口的鏈接,詳細介紹請見下表: spa

可是咱們無需都繼承這4個接口,SDK爲咱們提供了DefaultHandler類來處理,DefaultHandler類的一些主要事件回調方法以下: .net

由以上可知,咱們須要XmlReader 以及DefaultHandler來配合解析xml。 code

處理思路是: xml

1:建立SAXParserFactory對象 對象

2: 根據SAXParserFactory.newSAXParser()方法返回一個SAXParser解析器
3:根據SAXParser解析器獲取事件源對象XMLReader
4:實例化一個DefaultHandler對象 繼承

5:鏈接事件源對象XMLReader到事件處理類DefaultHandler中

6:調用XMLReader的parse方法從輸入源中獲取到的xml數據

7:經過DefaultHandler返回咱們須要的數據集合。

代碼以下:

View Code
複製代碼
   
public List < River > parse(String xmlPath){ List < River > rivers = null ; SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser parser = factory.newSAXParser(); // 獲取事件源 XMLReader xmlReader = parser.getXMLReader(); // 設置處理器 RiverHandler handler = new RiverHandler(); xmlReader.setContentHandler(handler); // 解析xml文檔 // xmlReader.parse(new InputSource(new URL(xmlPath).openStream())); xmlReader.parse( new InputSource( this .context.getAssets().open(xmlPath))); rivers = handler.getRivers(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return rivers; }
複製代碼

 重點在於DefaultHandler對象中對每個元素節點,屬性,文本內容,文檔內容進行處理。

 前面說過DefaultHandler是基於事件處理模型的,基本處理方式是:當SAX解析器導航到文檔開始標籤時回調startDocument方法,導航到文檔結束標籤時回調endDocument方法。當SAX解析器導航到元素開始標籤時回調startElement方法,導航到其文本內容時回調characters方法,導航到標籤結束時回調endElement方法。

 根據以上的解釋,咱們能夠得出如下處理xml文檔邏輯:

1:當導航到文檔開始標籤時,在回調函數startDocument中,能夠不作處理,固然你能夠驗證下UTF-8等等。

2:當導航到rivers開始標籤時,在回調方法startElement中能夠實例化一個集合用來存貯list,不過咱們這裏不用,由於在構造函數中已經實例化了。

3:導航到river開始標籤時,就說明須要實例化River對象了,固然river標籤中還有name ,length屬性,所以實例化River後還必須取出屬性值,attributes.getValue(NAME),同時賦予river對象中,同時添加爲導航到的river標籤添加一個boolean爲真的標識,用來講明導航到了river元素。

4:固然有river標籤內還有子標籤(節點),可是SAX解析器是不知道導航到什麼標籤的,它只懂得開始,結束而已。那麼如何讓它認得咱們的各個標籤呢?固然須要判斷了,因而可使用回調方法startElement中的參數String localName,把咱們的標籤字符串與這個參數比較下,就能夠了。咱們還必須讓SAX知道,如今導航到的是某個標籤,所以添加一個true屬性讓SAX解析器知道。所以

5:它還會導航到文本內標籤,(就是<img></img>裏面的內容),回調方法characters,咱們通常在這個方法中取出就是<img></img>裏面的內容,並保存。

6:固然它是必定會導航到結束標籤</river> 或者</rivers>的,若是是</river>標籤,記得把river對象添加進list中。若是是river中的子標籤</introduction>,就把前面設置標記導航到這個標籤的boolean標記設置爲false.

按照以上實現思路,能夠實現以下代碼:

View Code
複製代碼
   
/** 導航到開始標籤觸發* */ public void startElement (String uri, String localName, String qName, Attributes attributes){ String tagName = localName.length() != 0 ? localName:qName; tagName = tagName.toLowerCase().trim(); // 若是讀取的是river標籤開始,則實例化River if (tagName.equals(RIVER)){ isRiver = true ; river = new River(); /** 導航到river開始節點後* */ river.setName(attributes.getValue(NAME)); river.setLength(Integer.parseInt(attributes.getValue(LENGTH))); } // 而後讀取其餘節點 if (isRiver){ if (tagName.equals(INTRODUCTION)){ xintroduction = true ; } else if (tagName.equals(IMAGEURL)){ ximageurl = true ; } } } /** 導航到結束標籤觸發* */ public void endElement (String uri, String localName, String qName){ String tagName = localName.length() != 0 ? localName:qName; tagName = tagName.toLowerCase().trim(); // 若是讀取的是river標籤結束,則把River添加進集合中 if (tagName.equals(RIVER)){ isRiver = true ; rivers.add(river); } // 而後讀取其餘節點 if (isRiver){ if (tagName.equals(INTRODUCTION)){ xintroduction = false ; } else if (tagName.equals(IMAGEURL)){ ximageurl = false ; } } } // 這裏是讀取到節點內容時候回調 public void characters ( char [] ch, int start, int length){ // 設置屬性值 if (xintroduction){ // 解決null問題 river.setIntroduction(river.getIntroduction() == null ? "" :river.getIntroduction() + new String(ch,start,length)); } else if (ximageurl){ // 解決null問題 river.setImageurl(river.getImageurl() == null ? "" :river.getImageurl() + new String(ch,start,length)); } }
複製代碼

運行結果以下:

相關文章
相關標籤/搜索