詳解android使用SAX解析XML檔案_Android

來源:互聯網
上載者:User

解析XML的方式有很多種,大家比較熟悉的可能就是DOM解析。

DOM(檔案物件模型)解析:解析器讀入整個文檔,然後構建一個駐留記憶體的樹結構,然後代碼就可以根據DOM介面來操作這個樹結構了。

優點:整個文檔讀入記憶體,方便操作:支援修改、刪除和重現排列等多種功能。

缺點:將整個文檔讀入記憶體中,保留了過多的不需要的節點,浪費記憶體和空間。

使用場合:一旦讀入文檔,還需要多次對文檔進行操作,並且在硬體資源充足的情況下(記憶體,CPU)。

為瞭解決DOM解析存在的問題,就出現了SAX解析。其特點為:

優點:不用實現調入整個文檔,佔用資源少。尤其在嵌入式環境中,如android,極力推薦使用SAX解析。

缺點:不像DOM解析一樣將文檔長期駐留在記憶體中,資料不是持久的。如果事件過後沒有儲存資料,資料就會丟失。

使用場合:機器有效能限制。

SAX解析XML文檔採用事件驅動模式。什麼是事件驅動模式?它將XML文檔轉換成一系列的事件,由單獨的事件處理器來決定如何處理。

基於事件驅動的處理模式主要是基於事件來源和事件處理器(或者叫監聽器)來工作的。一個可以產生事件的對象叫做事件來源,而一個可以針對事件做出響應的對象就被叫做事件處理器。

在SAX介面中,事件來源是org.xml.sax包中的XMLReader,他通過parse()方法開始解析XML文檔,並根據文檔內容產生事件。而事件處理器則是org.xml.sax包中的ContentHandler、DTDHandler、ErrorHandler,以及EntityResolver這四個介面。他們分別處理事件來源在解析過程中產生不同類的事件(其中DTDHandler為解析文檔DTD時所用)。詳細介紹如下表:

在上述四個介面中,最重要的就是ContentHandler這個介面,下面是對這個介面方法的說明:

//設定一個可以定位文檔內容事件發生位置的定位器對象public void setDocumentLocator(Locator locator)//用於處理文檔解析開始事件public void startDocument()throws SAXException//處理元素開始事件,從參數中可以獲得元素所在名稱空間的uri,元素名稱,屬性類表等資訊public void startElement(String namespacesURI , String localName , String qName , Attributes atts) throws SAXException//處理元素結束事件,從參數中可以獲得元素所在名稱空間的uri,元素名稱等資訊public void endElement(String namespacesURI , String localName , String qName) throws SAXException//處理元素的字元內容,從參數中可以獲得內容public void characters(char[] ch , int start , int length) throws SAXException

這裡再介紹下XMLReader中的方法。

//註冊處理XML文檔解析事件ContentHandlerpublic void setContentHandler(ContentHandler handler)//開始解析一個XML文檔public void parse(InputSorce input) throws SAXException

SAX實現實體解析的步驟:

在android中使用SAX是有跡可循的,完全可以按照下面的方法就可以輕鬆找到xml裡的tag,然後得到想要的內容。具體實現步驟如下:

(一)第一步:建立一個工廠類SAXParserFactory,代碼如下:

SAXParserFactory factory = SAXParserFactory.newInstance();

(二)第二步:讓工廠類產生一個SAX的解析類SAXParser,代碼如下:

SAXParser parser = factory.newSAXParser();

(三)第三步:從SAXPsrser中得到一個XMLReader執行個體,代碼如下:

XMLReader reader = parser.getXMLReader();

(四)第四步:把自己寫的handler註冊到XMLReader中,一般最重要的就是ContentHandler,代碼如下:

RSSHandler handler = new RSSHandler();reader.setContentHandler(handler);

(五)第五步:將一個xml文檔或者資源變成一個java可以處理的InputStream流後,解析正式開始,代碼如下:

parser.parse(is);

上面幾個步驟中,最重要、最關鍵的就是第四步,handler的實現。

下面通過一個RSS解析的例子說明handler的實現:

我們先是自己見一個rss的xml文檔,實現本地解析,建立的rss文檔如下:

<?xml version="1.0" encoding="UTF-8"?>  <channel>    <title>RSS 解析練習</title>    <description>hehehaha</description>    <link>http://www.cnblogs.com/felix-hua/</link>    <language>zh-cn</language>    <item>      <title><![CDATA[頭條]]></title>      <link>http://mc.cz001.com.cn/images/menu/23_active.png</link>      <category>0</category>      <description>描述詳細資料的</description>      <pubDate>2012-01-09</pubDate>    </item>        <item>      <title><![CDATA[新聞]]></title>      <link>http://mc.cz001.com.cn/images/menu/23_active.png</link>      <category>0</category>      <description>描述詳細資料的</description>      <pubDate>2012-01-09</pubDate>    </item>        <item>      <title><![CDATA[首頁]]></title>      <link>http://mc.cz001.com.cn/images/menu/23_active.png</link>      <category>0</category>      <description>描述詳細資料的</description>      <pubDate>2012-01-09</pubDate>    </item>        <item>      <title><![CDATA[財經]]></title>      <link>http://mc.cz001.com.cn/images/menu/23_active.png</link>      <category>0</category>      <description>描述詳細資料的</description>      <pubDate>2012-01-09</pubDate>    </item>

建好後,我們命名為rssxml.xml,然後放到項目的根目錄下:

然後我們可以建立兩個實體類:

1、RSSFeed,與完整的xml文檔相對應;

2、RSSItem,與item標籤內的資訊相對應。

這樣在解析xml時,我們就可以把解析出來的資訊放到實體類裡,然後直接操作實體類就可以了。下面給出代碼:

RSSFeed.java

package com.sax.org.entity;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Vector;public class RSSFeed {  private String title;  private int itemcount;  private List<RSSItem> itemlist;    public RSSFeed(){    itemlist = new Vector<RSSItem>(0);  }    /**   * 負責將一個RSSItem加入到RSSFeed類中   * @param item   * @return   */  public int addItem(RSSItem item){    itemlist.add(item);    itemcount++;    return itemcount;  }    public RSSItem getItem(int location){    return itemlist.get(location);  }    public List<RSSItem> getAllItems(){    return itemlist;  }    /**   * 負責從RSSFeed類中產生列表所需要的資料   * @return   */  public List getAllItemForListView(){    List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();    int size = itemlist.size();    for(int i=0 ; i<size ; i++){      HashMap<String , Object> item = new HashMap<String, Object>();      item.put(RSSItem.TITLE, itemlist.get(i).getTitle());      item.put(RSSItem.PUBDATE, itemlist.get(i).getPubdate());      data.add(item);    }    return data;  }  public String getTitle() {    return title;  }  public void setTitle(String title) {    this.title = title;  }  public int getItemcount() {    return itemcount;  }  public void setItemcount(int itemcount) {    this.itemcount = itemcount;  }  public List<RSSItem> getItemlist() {    return itemlist;  }  public void setItemlist(List<RSSItem> itemlist) {    this.itemlist = itemlist;  }  }

RSSItem.java

package com.sax.org.entity;public class RSSItem {  public static String TITLE = "title";  public static String PUBDATE = "pubdate";  public String title;  public String description;  public String link;  public String category;  public String pubdate;  public RSSItem() {  }  public String getTitle() {    return title;  }  public void setTitle(String title) {    this.title = title;  }  public String getDescription() {    return description;  }  public void setDescription(String description) {    this.description = description;  }  public String getLink() {    return link;  }  public void setLink(String link) {    this.link = link;  }  public String getCategory() {    return category;  }  public void setCategory(String category) {    this.category = category;  }  public String getPubdate() {    return pubdate;  }  public void setPubdate(String pubdate) {    this.pubdate = pubdate;  }    }

下面就是最最重要的地方了,建立自己的ContentHandler.看下面的代碼:

RSSHandler.java

package com.sax.org.handler;import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;import com.sax.org.entity.RSSFeed;import com.sax.org.entity.RSSItem;public class RSSHandler extends DefaultHandler{  RSSFeed RssFeed;  RSSItem RssItem;  final int RSS_TITLE = 1;  final int RSS_LINK = 2;  final int RSS_DESCRIPTION = 3;  final int RSS_CATEGORY = 4;  final int RSS_PUBDATE = 5;  int currentstate = 0;    public RSSHandler(){}    public RSSFeed getFeed(){    return RssFeed;  }    @Override  public void startDocument() throws SAXException {    // TODO Auto-generated method stub    RssFeed = new RSSFeed();    RssItem = new RSSItem();  }    @Override  public void endDocument() throws SAXException {    // TODO Auto-generated method stub      }    @Override  public void startElement(String uri, String localName, String qName,      Attributes attributes) throws SAXException {    // TODO Auto-generated method stub    if(localName.equals("channel")){      currentstate = 0;      return;    }    if(localName.equals("item")){      RssItem = new RSSItem();      return;    }    if(localName.equals("title")){      currentstate = RSS_TITLE;      return;    }    if(localName.equals("description")){      currentstate = RSS_DESCRIPTION;      return;    }    if(localName.equals("link")){      currentstate = RSS_LINK;      return;    }    if(localName.equals("category")){      currentstate = RSS_CATEGORY;      return;    }    if(localName.equals("pubDate")){      currentstate = RSS_PUBDATE;      return;    }    currentstate = 0;  }    @Override  public void endElement(String uri, String localName, String qName)      throws SAXException {    // TODO Auto-generated method stub    if(localName.equals("item")){      RssFeed.addItem(RssItem);      return;    }  }    @Override  public void characters(char[] ch, int start, int length)      throws SAXException {    // TODO Auto-generated method stub    String theString = new String(ch, start, length);    switch(currentstate){    case RSS_TITLE:      RssItem.setTitle(theString);      currentstate = 0;      break;    case RSS_DESCRIPTION:      RssItem.setDescription(theString);      currentstate = 0;      break;    case RSS_LINK:      RssItem.setLink(theString);      currentstate = 0;      break;    case RSS_PUBDATE:      RssItem.setPubdate(theString);      currentstate = 0;      break;    case RSS_CATEGORY:      RssItem.setCategory(theString);      currentstate = 0;      break;    default:      return;    }  }}

就上面的程式碼分析,實現一個ContentHandler一般要一下幾個步驟:

1、聲明一個類,繼承DefaultHandler。DefaultHandler是一個基類,這個類裡面簡單實現了一個ContentHandler。我們只需要重寫裡面的方法即可。

2、重寫 startDocument() 和 endDocument(),一般解析將正式解析之前的一些初始化工資放到startDocument()裡面,收尾的工作放到endDocument()裡面。

3、重寫startElement(),XML解析器遇到XML裡面的tag時就會調用這個函數。經常在這個函數內是通過localName倆進行判斷而操作一些資料。

4、重寫characters()方法,這是一個回調方法。解析器執行完startElement()後,解析完節點的內容後就會執行這個方法,並且參數ch[]就是節點的內容。這個例子裡我們根據currentstate的不同,來判斷當前那個tag的內容,並放到合適的實體類中。

5、重寫endElement()方法,這個方法與startElement()相對應,解析完一個tag節點後,執行這個方法。再找個例子中,如果解析一個item結束,就將RSSIiem添加到RSSFeed中。

最後我們實現一個activity來展現解析的結果:

 package com.sax.org;import java.io.IOException;import java.net.URL;import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import org.xml.sax.InputSource;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import android.app.Activity;import android.os.Bundle;import android.widget.ListView;import android.widget.SimpleAdapter;import android.widget.TextView;import com.sax.org.entity.RSSFeed;import com.sax.org.entity.RSSItem;import com.sax.org.handler.RSSHandler;public class SAXReaderActivity extends Activity {  /** Called when the activity is first created. */  public String rssUrl = "http://mc.cz001.com.cn/a/indexconfig/index.rss";  public RSSFeed feed;  @Override  public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    feed = getFeed(rssUrl);    showList();  }  public RSSFeed getFeed(String rssUrl) {    try {// 這裡我們實現了本地解析,所以注掉了這個取網路資料的。//      URL url = new URL(rssUrl);      SAXParserFactory factory = SAXParserFactory.newInstance();      SAXParser parser = factory.newSAXParser();      XMLReader reader = parser.getXMLReader();      RSSHandler handler = new RSSHandler();      reader.setContentHandler(handler);      InputSource is = new InputSource(this.getClassLoader().getResourceAsStream("rssxml.xml"));//取得本地xml檔案      reader.parse(is);      return handler.getFeed();    } catch (ParserConfigurationException e) {      // TODO Auto-generated catch block      e.printStackTrace();    } catch (SAXException e) {      // TODO Auto-generated catch block      e.printStackTrace();    } catch (IOException e) {      // TODO Auto-generated catch block      e.printStackTrace();    }    return null;  }  public void showList() {    ListView rsslistview = (ListView) findViewById(R.id.rssList);    TextView rsstitle = (TextView) findViewById(R.id.rsstitle);    if (feed == null) {      rsstitle.setText("訪問失敗...");      return;    }    SimpleAdapter adapter = new SimpleAdapter(this,        feed.getAllItemForListView(),        android.R.layout.simple_list_item_2, new String[] {            RSSItem.TITLE, RSSItem.PUBDATE }, new int[] {            android.R.id.text1, android.R.id.text2 });    rsslistview.setAdapter(adapter);  }}

展示下運行結果:

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.