RSS阅读器练习笔记————xml文件解析中CDATA及HTML字符实体的处理

来源:互联网 发布:淘宝限购一件怎么破解 编辑:程序博客网 时间:2024/05/02 16:47

本文来自http://blog.csdn.net/chenshaoyang0011转载请申明出处!

本文将介绍本人在写RSS阅读器时,解析RSS的xml文件所遇到的一些问题和解决方法。

首先简单介绍下什么是RSS:RSS简易信息聚合)是一种消息来源格式规范,用以聚合经常发布更新数据的网站,例如文章、博客,音频或视频

的网摘。(摘自Wiki)

一个站点若提供RSS源,我们就可以从这个站点获取RSS文件,而这个RSS文件就是使用xml这种格式来封装和传递数据。

简单了解了RSS之后,开始进入正题。终端得到xml文件之后,就需要开始解析xml来获取数据。Android中解析XML的比较常见的方法有三种:1、DOM解

析;2、SAX解析;3、PULL解析。具体如何使用,网上有很多教程这里就不再赘述了,这里着重讲下我在解析RSS的XML遇到的两个问题:1、标签中

包含CDATA;2、字符串中包含HTML字符实体。

以下均以SAX方法进行解析,使用其它解析方法可以参照进行修改。

一、标签中包含CDATA的解决办法

首先可以先了解下CDATAhttp://www.w3school.com.cn/xml/xml_cdata.asp。简单的说就是在XML中CDATA后面的内容将不会被解析器解析。而这么做

的原因是为了避免一些字符扰乱解析的过程。为了了解CDATA的影响,先看下面一个例子:

解析一个xml文件,文件内容如下:

<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title><![CDATA[&lt;体育要闻汇总&nbsp-新浪娱乐]]></title><description><![CDATA[体育要闻汇总]]></description></channel></rss>
使用SAX方法进行解析,使用到的MyHandler的代码片段如下:

public class MyHandler extends DefaultHandler {private static String TAG = "MyHandler";@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {String str = new String(ch, start, length); Log.i(TAG, "characters : " + str);super.characters(ch, start, length);}@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {Log.i(TAG, "endElement : " + localName);super.endElement(uri, localName, qName);}@Overridepublic void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {Log.i(TAG, "startElement : " + localName);super.startElement(uri, localName, qName, attributes);}}
这样解析之后,获得输出的结果如下:

03-04 20:40:52.614: I/MyHandler(23006): startElement : rss03-04 20:40:52.614: I/MyHandler(23006): characters : 03-04 20:40:52.614: I/MyHandler(23006): characters : 03-04 20:40:52.617: I/MyHandler(23006): startElement : channel03-04 20:40:52.617: I/MyHandler(23006): characters : 03-04 20:40:52.617: I/MyHandler(23006): characters : 03-04 20:40:52.617: I/MyHandler(23006): startElement : title03-04 20:40:52.617: I/MyHandler(23006): characters : 03-04 20:40:52.617: I/MyHandler(23006): characters : 03-04 20:40:52.617: I/MyHandler(23006): characters : &lt;体育要闻汇总&nbsp-新浪娱乐03-04 20:40:52.617: I/MyHandler(23006): characters : 03-04 20:40:52.617: I/MyHandler(23006): characters : 03-04 20:40:52.617: I/MyHandler(23006): endElement : title03-04 20:40:52.617: I/MyHandler(23006): characters : 03-04 20:40:52.617: I/MyHandler(23006): characters : 03-04 20:40:52.617: I/MyHandler(23006): startElement : description03-04 20:40:52.617: I/MyHandler(23006): characters : 03-04 20:40:52.620: I/MyHandler(23006): characters : 03-04 20:40:52.620: I/MyHandler(23006): characters : 体育要闻汇总03-04 20:40:52.620: I/MyHandler(23006): characters : 03-04 20:40:52.620: I/MyHandler(23006): characters : 03-04 20:40:52.620: I/MyHandler(23006): endElement : description03-04 20:40:52.620: I/MyHandler(23006): characters : 03-04 20:40:52.620: I/MyHandler(23006): characters : 03-04 20:40:52.620: I/MyHandler(23006): endElement : channel03-04 20:40:52.620: I/MyHandler(23006): characters : 03-04 20:40:52.620: I/MyHandler(23006): endElement : rss

可以看到,解析到某个标签时,characters方法被多次调用,如果只在characters中处理一次那样我们无法获取到正确的数据。那么解决的方法就是在解析某

个标签时,将每次在characters中获取的字符串进行“连接”。按照此思路,修改MyHandler类,代码片段如下:

public class MyHandler extends DefaultHandler {StringBuffer stringBuffer;private static String TAG = "MyHandler";@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {String str = new String(ch, start, length);if(!TextUtils.isEmpty(str)){stringBuffer.append(ch, start, length);}super.characters(ch, start, length);}@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {Log.i(TAG, "endElement : " + localName + " , str : " + stringBuffer.toString());if(qName.equals("title")){title = stringBuffer.toString();}super.endElement(uri, localName, qName);}@Overridepublic void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {Log.i(TAG, "startElement : " + localName);stringBuffer = new StringBuffer();super.startElement(uri, localName, qName, attributes);}}

解析之后,获得的输出结果如下:

03-04 20:51:39.877: I/MyHandler(23858): startElement : rss03-04 20:51:39.877: I/MyHandler(23858): startElement : channel03-04 20:51:39.880: I/MyHandler(23858): startElement : title03-04 20:51:39.884: I/MyHandler(23858): endElement : title , str : 03-04 20:51:39.884: I/MyHandler(23858): &lt;体育要闻汇总&nbsp-新浪娱乐03-04 20:51:39.884: I/MyHandler(23858): 03-04 20:51:39.884: I/MyHandler(23858): startElement : description03-04 20:51:39.884: I/MyHandler(23858): endElement : description , str : 03-04 20:51:39.884: I/MyHandler(23858): 体育要闻汇总03-04 20:51:39.884: I/MyHandler(23858): 03-04 20:51:39.884: I/MyHandler(23858): endElement : channel , str : 03-04 20:51:39.884: I/MyHandler(23858): 体育要闻汇总03-04 20:51:39.884: I/MyHandler(23858): 03-04 20:51:39.884: I/MyHandler(23858): 03-04 20:51:39.884: I/MyHandler(23858): endElement : rss , str : 03-04 20:51:39.884: I/MyHandler(23858): 体育要闻汇总03-04 20:51:39.884: I/MyHandler(23858): 03-04 20:51:39.884: I/MyHandler(23858): 

这样处理之后,标签中的数据就被我们抓出来了。

二、字符串中包含HTML字符实体的解决方法。

很多RSS源提供的XML中会包含一些HTML字符实体,这些HTML字符实体包含在CDATA所包含的数据中。如果对HTML字符实体不清楚,可以参照

http://114.xixik.com/character/。

对于这些HTML字符实体,一个比较笨的方法是使用正则表达式等方法进行判断然后再进行处理。幸运的是,Android中封装了一些类可以对其进行很

好的处理。Html类就可以对符合Html编码规则的内容自动进行处理。如果获取的字符串(String)str中包含字符实体,则可以通过以下代码进行处理:

while(str.contains("&")){str = Html.fromHtml(str).toString();}
使用此方法修改MyHandler如下:

public class MyHandler extends DefaultHandler {StringBuffer stringBuffer;private static String TAG = "MyHandler";@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {String str = new String(ch, start, length);if(!TextUtils.isEmpty(str)){stringBuffer.append(ch, start, length);}super.characters(ch, start, length);}@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {String str = stringBuffer.toString();while(str.contains("&")){str = Html.fromHtml(str).toString();}Log.i(TAG, "endElement : " + localName + " , str : " + str);super.endElement(uri, localName, qName);}@Overridepublic void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {Log.i(TAG, "startElement : " + localName);stringBuffer = new StringBuffer();super.startElement(uri, localName, qName, attributes);}}

修改后程序的输出结果如下:

03-04 21:11:42.559: I/MyHandler(25831): startElement : rss03-04 21:11:42.559: I/MyHandler(25831): startElement : channel03-04 21:11:42.559: I/MyHandler(25831): startElement : title03-04 21:11:42.566: I/MyHandler(25831): endElement : title , str : <体育要闻汇总?-新浪娱乐 03-04 21:11:42.566: I/MyHandler(25831): startElement : description03-04 21:11:42.566: I/MyHandler(25831): endElement : description , str : 03-04 21:11:42.566: I/MyHandler(25831): 体育要闻汇总03-04 21:11:42.566: I/MyHandler(25831): 03-04 21:11:42.566: I/MyHandler(25831): endElement : channel , str : 03-04 21:11:42.566: I/MyHandler(25831): 体育要闻汇总03-04 21:11:42.566: I/MyHandler(25831): 03-04 21:11:42.566: I/MyHandler(25831): 03-04 21:11:42.566: I/MyHandler(25831): endElement : rss , str : 03-04 21:11:42.566: I/MyHandler(25831): 体育要闻汇总03-04 21:11:42.566: I/MyHandler(25831): 03-04 21:11:42.566: I/MyHandler(25831): 

这样HTML字符实体就成功的被“消化”了。

最后附上一个简单的demohttp://download.csdn.net/detail/chenshaoyang0011/5108958


原创粉丝点击