Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android RSS客戶端開發實例之二:如何解析XML文件

Android RSS客戶端開發實例之二:如何解析XML文件

編輯:Android開發實例

       在RSS概述中簡單介紹了RSS,本節將為大家講解RSS文件的解析,而又因為RSS是用XML編寫的,所以這裡就直接為大家講解怎樣解析XML文件。

       一、XML文件解析方式

       解析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時所用)。

       SAX是一種占用內存少且解析速度快的解析器,它采用的是事件啟動,它不需要解析完整個文檔,而是按照內容順序 看文檔某個部分是否符合xml語法,如果符合就觸發相應的事件,所謂的事件就是些回調方法(callback),這些方法定義在ContentHandler中,下面是其主要方法:

       startDocument:當遇到文檔的時候就觸發這個事件,調用這個方法可以在其中做些預處理工作。

       startElement(String namespaceURI,String localName,String qName,Attributes atts):當遇開始標簽的時候就會觸發這個方法。

       endElement(String uri,String localName,String name):當遇到結束標簽時觸發這個事件,調用此法可以做些善後工作。

       charachers(char [] ch,int start,int length):當遇到xml內容時觸發這個方法,用new String(ch,start,length)可以接受內容。 

       二、建立pojo類

       在解析之前,我們需要建立pojo類來對應RSS中的元素。首先是RSS feed,我們知道<channel> 元素用於描述RSS feed,但它不是描述RSS的重點,它下面的三個必須子元素<title><link><description>是描述feed的主要信息。因為我們在解析之前就事先獲取了RSS地址,所以在這裡我們就不需要建立一個RSS的link了。主要建立link,item列表以及description,因為是標題,所以把description就換成時間來表達,一般的RSS也是這樣做的。如圖:

Android RSS標題

       下面是建立的RSSFeed:

Java代碼
  1. public class RSSFeed    
  2. {   
  3. private String title = null;標題   
  4. private String pubdate = null;發布日期   
  5. private int itemcount = 0;//用於計算列表數目   
  6. private List<RSSItem> itemlist;聲明一個RSSItem類型的泛型集合類List對象itemlist,用於描述列表 item   
  7.  public RSSFeed()   
  8. {   
  9. itemlist = new Vector(0); 構造函數初始化itemlist   
  10. }   
  11. public int addItem(RSSItem item)   
  12. {   
  13. itemlist.add(item);   
  14. itemcount++;   
  15. return itemcount;   
  16. }   
  17. public RSSItem getItem(int location)   
  18. {   
  19. return itemlist.get(location);   
  20. }   
  21. public List getAllItems()   
  22. {   
  23. return itemlist;   
  24. }   
  25. public List getAllItemsForListView(){   
  26. List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();   
  27. int size = itemlist.size();   
  28. for(int i=0;i<size;i++){   
  29. HashMap<String, Object>item = new HashMap<String, Object>();   
  30. item.put(RSSItem.TITLE, itemlist.get(i).getTitle());   
  31. item.put(RSSItem.PUBDATE, itemlist.get(i).getPubDate());   
  32. data.add(item);   
  33. }   
  34. return data;   
  35. }   
  36. int getItemCount()   
  37. {   
  38. return itemcount;   
  39. }   
  40. public void setTitle(String title)   
  41. {   
  42. this.title = title;   
  43. }   
  44. public void setPubDate(String pubdate)   
  45. {   
  46. this.pubdate = pubdate;   
  47. }   
  48. public String getTitle()   
  49. {   
  50. return title;   
  51. }   
  52. public String getPubDate()   
  53. {   
  54. return pubdate;   
  55. }   
  56. }  

       建立完RSSFeed類後,我們開始建立RSSItem:

Java代碼
  1. public static final String TITLE="title";   
  2. public static final String PUBDATE="pubdate";   
  3. private String title = null;   
  4. private String description = null;   
  5. private String link = null;   
  6. private String category = null;   
  7. private String pubdate = null;   
  8.           
  9.   
  10.         public RSSItem()   
  11. {   
  12. }   
  13. public void setTitle(String title)   
  14. {   
  15. this.title = title;   
  16. }   
  17. public void setDescription(String description)   
  18. {   
  19. this.description = description;   
  20. }   
  21. public void setLink(String link)   
  22. {   
  23. this.link = link;   
  24. }   
  25. public void setCategory(String category)   
  26. {   
  27. this.category = category;   
  28. }   
  29. public void setPubDate(String pubdate)   
  30. {   
  31. this.pubdate = pubdate;   
  32. }   
  33. public String getTitle()   
  34. {   
  35. return title;   
  36. }   
  37. public String getDescription()   
  38. {   
  39. return description;   
  40. }   
  41. public String getLink()   
  42. {   
  43. return link;   
  44. }   
  45. public String getCategory()   
  46. {   
  47. return category;   
  48. }   
  49. public String getPubDate()   
  50. {   
  51. return pubdate;   
  52. }   
  53. public String toString()   
  54. {   
  55. if (title.length() > 20)   
  56. {   
  57. return title.substring(0, 42) + "...";   
  58. }   
  59. return title;   
  60. }   
  61. }  

       三、XML解析

       新建helper類RSSHandler,用於對rss進行xml解析,並將解析結果包裝為RSSFeed和RSSItem對象,方便在UI界面中顯示:

Java代碼
  1. public class RSSHandler extends DefaultHandler    
  2. {   
  3.   
  4. RSSFeed rssFeed;//用於保存解析過程中的channel   
  5. RSSItem rssItem;//用於保存解析過程中的item   
  6. String lastElementName = ""; //標記變量,用於標記在解析過程中我們關心的幾個標簽,若不是我們關心的標簽,記做 0   
  7. final int RSS_TITLE = 1;//若是title標簽,記做 1,注意有兩個title,但我們都保存在item的title成員變量中   
  8. final int RSS_LINK = 2;//若是link標簽,記做 2   
  9. final int RSS_DESCRIPTION = 3;//若是description標簽,記做 3   
  10. final int RSS_CATEGORY = 4;//若是category標簽,記做 4   
  11. final int RSS_PUBDATE = 5; //若是pubdate標簽,記做 5,注意有兩個pubdate,但我們都保存在item的pubdate成員變量中   
  12. int currentstate = 0;   
  13.   
  14.         public RSSHandler(){}   
  15. public RSSFeed getFeed()   
  16. {   
  17. return rssFeed;//通過這個方法把解析結果封裝在 RSSFeed 對象中並返回   
  18. }   
  19.   
  20.  //下面通過重載 DefaultHandler 的 5 個方法來實現 sax 解析   
  21. public void startDocument() throws SAXException   
  22. {   
  23.   
  24.                 //這個方法在解析xml文檔的一開始執行,一般我們需要在該方法中初始化解析過程中有可能用到的變量   
  25. rssFeed = new RSSFeed();   
  26. rssItem = new RSSItem();   
  27.         }   
  28. public void endDocument() throws SAXException   
  29. {   
  30.   
  31. //這個方法在整個xml文檔解析結束時執行,一般需要在該方法中返回或保存整個文檔解析解析結果,但由於   
  32.   
  33.      //我們已經在解析過程中把結果保持在rssFeed中,所以這裡什麼也不做   
  34.   
  35.   
  36. }   
  37. public void startElement(String namespaceURI, String localName,String qName, Attributes atts) throws SAXException   
  38. {    
  39. //這個方法在解析標簽開始標記時執行,一般我們需要在該方法取得標簽屬性值,但由於我們的rss文檔   
  40.   
  41.      //中並沒有任何我們關心的標簽屬性,因此我們主要在這裡進行的是設置標記變量currentstate,以   
  42.   
  43.      //標記我們處理到哪個標簽   
  44.   
  45.   
  46. if (localName.equals("channel"))   
  47. {//channel這個標簽沒有任何值得我們關心的內容,所以currentstate置為0   
  48. currentstate = 0;   
  49. return;   
  50. }   
  51. if (localName.equals("item"))   
  52. {    
  53. //若是item標簽,則重新構造一個RSSItem,從而把已有(已經解析過的)item數據扔掉,當   
  54.   
  55.  //然事先是已經保存到rssFeed的itemlist集合中了   
  56.   
  57.   
  58. rssItem = new RSSItem();   
  59. return;   
  60. }   
  61. if (localName.equals("title"))   
  62. {    
  63. //若是title標簽,置currentstate為1,表明這是我們關心的數據,這樣在characters   
  64.   
  65.  //方法中會把元素內容保存到rssItem變量中   
  66.   
  67.   
  68. currentstate = RSS_TITLE;   
  69. return;   
  70. }   
  71. if (localName.equals("description"))   
  72. {    
  73. //若是description標簽,置currentstate為3,表明這是我們關心的數據,這樣在characters   
  74.   
  75.  //方法中會把元素內容保存到rssItem變量中   
  76.   
  77.   
  78. currentstate = RSS_DESCRIPTION;   
  79. return;   
  80. }   
  81. if (localName.equals("link"))   
  82. {    
  83. //若是link標簽,置currentstate為2,表明這是我們關心的數據,這樣在characters   
  84.   
  85.  //方法中會把元素內容保存到rssItem變量中   
  86.   
  87.   
  88. currentstate = RSS_LINK;   
  89. return;   
  90. }   
  91. if (localName.equals("category"))   
  92. {    
  93. //若是category標簽,置currentstate為4,表明這是我們關心的數據,這樣在characters   
  94.   
  95.  //方法中會把元素內容保存到rssItem變量中   
  96.   
  97.   
  98. currentstate = RSS_CATEGORY;   
  99. return;   
  100. }   
  101. if (localName.equals("pubDate"))   
  102. {    
  103. //若是pubDate標簽,置currentstate為5,表明這是我們關心的數據,這樣在characters   
  104.   
  105.  //方法中會把元素內容保存到rssItem變量中   
  106.   
  107.   
  108. currentstate = RSS_PUBDATE;   
  109. return;   
  110. }   
  111.   
  112. currentstate = 0;//如果不是上面列出的任何標簽,置currentstate為0,我們不關心   
  113. }   
  114.   
  115. public void endElement(String namespaceURI, String localName, String qName) throws SAXException   
  116. {   
  117.   
  118.   
  119. //如果解析一個item節點結束,就將rssItem添加到rssFeed中。   
  120. if (localName.equals("item"))   
  121. {   
  122. rssFeed.addItem(rssItem);   
  123. return;   
  124.   
  125. }   
  126. }   
  127.     
  128. public void characters(char ch[], int start, int length)   
  129. {//這個方法在解析標簽內容(即開始標記-結束標記之間的部分)時執行,一般我們在裡這獲取元素體內容   
  130. String theString = new String(ch,start,length); //獲取元素體內容   
  131. switch (currentstate)   
  132. {//根據currentstate標記判斷這個元素體是屬於我們關心的哪個元素   
  133. case RSS_TITLE:   
  134. rssItem.setTitle(theString);//若是title元素,放入rssItem的title屬性   
  135. currentstate = 0;   
  136. break;   
  137. case RSS_LINK:   
  138. rssItem.setLink(theString);//若是link元素,放入rssItem的link屬性   
  139. currentstate = 0;   
  140. break;   
  141. case RSS_DESCRIPTION:   
  142. rssItem.setDescription(theString);   
  143. currentstate = 0;   
  144. break;   
  145. case RSS_CATEGORY:   
  146. rssItem.setCategory(theString);   
  147. currentstate = 0;   
  148. break;   
  149. case RSS_PUBDATE:   
  150. rssItem.setPubDate(theString);   
  151. currentstate = 0;   
  152. break;   
  153. default:   
  154. return;   
  155. }   
  156.   
  157. }   
  158.   
  159. }  

       之後就可以按照一定的步驟來進行解析了,具體如下:

Java代碼
  1. private RSSFeed getFeed(String urlString)   
  2. {   
  3.     try  
  4.     {   
  5.       URL url = new URL(urlString);   
  6.           SAXParserFactory factory = SAXParserFactory.newInstance();  // 構建Sax解析工廠   
  7.            SAXParser parser = factory.newSAXParser(); // 使用Sax解析工廠構建Sax解析器   
  8.            XMLReader xmlreader = parser.getXMLReader();   // 使用Sax解析器構建xml Reader   
  9.               
  10.            RSSHandler rssHandler = new RSSHandler(); // 構建自定義的RSSHandler作為xml Reader的處理器(或代理)   
  11.            xmlreader.setContentHandler(rssHandler);     // 構建自定義的RSSHandler作為xml Reader的處理器(或代理)   
  12.   
  13.   
  14.            InputSource is = new InputSource(url.openStream());      // 使用url打開流,並將流作為xml Reader的輸入源並解析   
  15.            xmlreader.parse(is);   
  16.      
  17.            return rssHandler.getFeed();     // 將解析結果作為 RSSFeed 對象返回   
  18.     }   
  19.     catch (Exception ee)   
  20.     {   
  21.   
  22.   
  23.     return null;   
  24.     }   
  25. }  

       關於如何解析RSS文件就先講這些。後面一節我們將介紹怎樣在列表裡顯示RSS內容,望大家繼續關注。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved