在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(042) + "...";   
  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内容,望大家继续关注。

本文发布:Android开发网
本文地址:http://www.jizhuomi.com/android/example/146.html
2012年8月6日
发布:鸡啄米 分类:Android开发实例 浏览: 评论:0