Android实例RSS客户端开发(2)--解析XML文件

By | 06月01日
Advertisement

介绍完RSS之后,下面开始讲解如何解析RSS文件。因为RSS是基于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客户端开发(2)--解析XML文件

下面是建立的RSSFeed:

public class RSSFeed
{
private String title = null;标题
private String pubdate = null;发布日期
private int itemcount = 0;//用于计算列表数目
private List<RSSItem> itemlist;声明一个RSSItem类型的泛型集合类List对象itemlist,用于描述列表item
public RSSFeed()
{
itemlist = new Vector(0); 构造函数初始化itemlist
}
public int addItem(RSSItem item)
{
itemlist.add(item);
itemcount++;
return itemcount;
}
public RSSItem getItem(int location)
{
return itemlist.get(location);
}
public List getAllItems()
{
return itemlist;
}
public List getAllItemsForListView(){
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;
}
int getItemCount()
{
return itemcount;
}
public void setTitle(String title)
{
this.title = title;
}
public void setPubDate(String pubdate)
{
this.pubdate = pubdate;
}
public String getTitle()
{
return title;
}
public String getPubDate()
{
return pubdate;
}
}

建立完RSSFeed 类后,我们开始建立RSSItem
public static final String TITLE="title";
public static final String PUBDATE="pubdate";
private String title = null;
private String description = null;
private String link = null;
private String category = null;
private String pubdate = null;

public RSSItem()
{
}
public void setTitle(String title)
{
this.title = title;
}
public void setDescription(String description)
{
this.description = description;
}
public void setLink(String link)
{
this.link = link;
}
public void setCategory(String category)
{
this.category = category;
}
public void setPubDate(String pubdate)
{
this.pubdate = pubdate;
}
public String getTitle()
{
return title;
}
public String getDescription()
{
return description;
}
public String getLink()
{
return link;
}
public String getCategory()
{
return category;
}
public String getPubDate()
{
return pubdate;
}
public String toString()
{
if (title.length() > 20)
{
return title.substring(0, 42) + "...";
}
return title;
}
}

三 解析

新建helper类RSSHandler,用于对rss进行xml解析,并将解析结果包装为RSSFeed和RSSItem对象,方便在ui界面中显示:

public class RSSHandler extends DefaultHandler
{

RSSFeed rssFeed;//用于保存解析过程中的channel
RSSItem rssItem;//用于保存解析过程中的item
String lastElementName = "";//标记变量,用于标记在解析过程中我们关心的几个标签,若不是我们关心的标签,记做0
final int RSS_TITLE = 1;//若是title标签,记做1,注意有两个title,但我们都保存在item的title成员变量中
final int RSS_LINK = 2;//若是link标签,记做2
final int RSS_DESCRIPTION = 3;//若是description标签,记做3
final int RSS_CATEGORY = 4;//若是category标签,记做4
final int RSS_PUBDATE = 5;//若是pubdate标签,记做5,注意有两个pubdate,但我们都保存在item的pubdate成员变量中
int currentstate = 0;

public RSSHandler(){}
public RSSFeed getFeed()
{
return rssFeed;//通过这个方法把解析结果封装在RSSFeed对象中并返回
}

//下面通过重载DefaultHandler的5个方法来实现sax解析
public void startDocument() throws SAXException
{

//这个方法在解析xml文档的一开始执行,一般我们需要在该方法中初始化解析过程中有可能用到的变量
rssFeed = new RSSFeed();
rssItem = new RSSItem();
}
public void endDocument() throws SAXException
{

//这个方法在整个xml文档解析结束时执行,一般需要在该方法中返回或保存整个文档解析解析结果,但由于

//我们已经在解析过程中把结果保持在rssFeed中,所以这里什么也不做

}
public void startElement(String namespaceURI, String localName,String qName, Attributes atts) throws SAXException
{

//这个方法在解析标签开始标记时执行,一般我们需要在该方法取得标签属性值,但由于我们的rss文档

//中并没有任何我们关心的标签属性,因此我们主要在这里进行的是设置标记变量currentstate,以

//标记我们处理到哪个标签

if (localName.equals("channel"))
{//channel这个标签没有任何值得我们关心的内容,所以currentstate置为0
currentstate = 0;
return;
}
if (localName.equals("item"))
{

//若是item标签,则重新构造一个RSSItem,从而把已有(已经解析过的)item数据扔掉,当

//然事先是已经保存到rssFeed的itemlist集合中了

rssItem = new RSSItem();
return;
}
if (localName.equals("title"))
{

//若是title标签,置currentstate为1,表明这是我们关心的数据,这样在characters

//方法中会把元素内容保存到rssItem变量中

currentstate = RSS_TITLE;
return;
}
if (localName.equals("description"))
{

//若是description标签,置currentstate为3,表明这是我们关心的数据,这样在characters

//方法中会把元素内容保存到rssItem变量中

currentstate = RSS_DESCRIPTION;
return;
}
if (localName.equals("link"))
{

//若是link标签,置currentstate为2,表明这是我们关心的数据,这样在characters

//方法中会把元素内容保存到rssItem变量中

currentstate = RSS_LINK;
return;
}
if (localName.equals("category"))
{

//若是category标签,置currentstate为4,表明这是我们关心的数据,这样在characters

//方法中会把元素内容保存到rssItem变量中

currentstate = RSS_CATEGORY;
return;
}
if (localName.equals("pubDate"))
{

//若是pubDate标签,置currentstate为5,表明这是我们关心的数据,这样在characters

//方法中会把元素内容保存到rssItem变量中

currentstate = RSS_PUBDATE;
return;
}

currentstate = 0;//如果不是上面列出的任何标签,置currentstate为0,我们不关心
}

public void endElement(String namespaceURI, String localName, String qName) throws SAXException
{

//如果解析一个item节点结束,就将rssItem添加到rssFeed中。
if (localName.equals("item"))
{
rssFeed.addItem(rssItem);
return;

}
}

public void characters(char ch[], int start, int length)
{//这个方法在解析标签内容(即开始标记-结束标记之间的部分)时执行,一般我们在里这获取元素体内容
String theString = new String(ch,start,length);//获取元素体内容
switch (currentstate)
{//根据currentstate标记判断这个元素体是属于我们关心的哪个元素
case RSS_TITLE:
rssItem.setTitle(theString);//若是title元素,放入rssItem的title属性
currentstate = 0;
break;
case RSS_LINK:
rssItem.setLink(theString);//若是link元素,放入rssItem的link属性
currentstate = 0;
break;
case RSS_DESCRIPTION:
rssItem.setDescription(theString);
currentstate = 0;
break;
case RSS_CATEGORY:
rssItem.setCategory(theString);
currentstate = 0;
break;
case RSS_PUBDATE:
rssItem.setPubDate(theString);
currentstate = 0;
break;
default:
return;
}

}

}

之后就可以按照一定的步骤来进行解析了,具体如下:

private RSSFeed getFeed(String urlString)
{
try
{
URL url = new URL(urlString);
SAXParserFactory factory = SAXParserFactory.newInstance();//构建Sax解析工厂
SAXParser parser = factory.newSAXParser();//使用Sax解析工厂构建Sax解析器
XMLReader xmlreader = parser.getXMLReader();//使用Sax解析器构建xmlReader

RSSHandler rssHandler = new RSSHandler();//构建自定义的RSSHandler作为xmlReader的处理器(或代理)
xmlreader.setContentHandler(rssHandler); //构建自定义的RSSHandler作为xmlReader的处理器(或代理)

InputSource is = new InputSource(url.openStream()); //使用url打开流,并将流作为xmlReader的输入源并解析
xmlreader.parse(is);

return rssHandler.getFeed(); //将解析结果作为RSSFeed对象返回
}
catch (Exception ee)
{

return null;
}
}

RSS文件的解析就介绍到这里,之后我们开始实现如何在列表里显示RSS内容了。

Similar Posts:

  • Android网络编程之三:XmlPullParser解析Xml文件

    由于XmlPullParser有不同的版本,PC端的与Android端好多地方处理问题的方式都不同. PC端的下载地址:XmlPullParser下载 Android本身就集成得有这种处理问题的类,闲话少扯,来点真实的: 1.Xml文件,参照之一 2.定义一个ListViewItem的layout文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="

  • 【Android学习笔记】XmlResourceParser解析xml文件

    最近学习Android时,需要用到解析XML文件里的数据,可以用XmlResourceParser来解析xml文件,正好将此记录下来. XmlResourceParser里常用的字段和方法 首先先给出源码里面一些比较基础的,常用的方法和字段. 常用的字段 int START_DOCUMENT = 0; int END_DOCUMENT = 1; int START_TAG = 2; int END_TAG = 3; int TEXT = 4; getEventType() /** * Retur

  • android 三种解析xml文件方法总结

    在Android平台上可以使用Simple API for XML(SAX) . Document Object Model(DOM)和Android附带的pull解析器解析XML文件. 下面是本例子要解析的XML文件:itcast.xml <?xml version="1.0" encoding="UTF-8"?> <persons> <person id="23"> <name>李明</n

  • Java-使用SAX,DOM,pull解析XML文件以及pull解析生成xml文件

    使用SAX或者DOM或者pull解析XML文件 在Android平台上可以使用Simple API for XML(SAX) . Document Object Model(DOM)和Android附带的pull解析器解析XML文件. 下面是本例子要解析的XML文件: 文件名称:csdn.xml <?xml version="1.0" encoding="UTF-8"?> <persons> <person id="23&qu

  • Android开发之使用pull解析xml文件

    XML在Android中是非常常见用来保存数据的文件,解析的方法也很多,如:DOM.SAX.PULL,其中PULL是Android自带的解析XML方法 DOM:是一次性加载完,生成树状结构,但消耗内存较大,如果这个xml文件比较大就不适合使用DOM来解析 SAX:是基于事件的方式,边加载边解析,效率较高,但解析过不能倒退 PULL:跟ASX有点类似,也是基于事件 程序目录结构 使用pull解析 package com.example.xmlpullparserdemo.service; impo

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

    转载:http://www.cnblogs.com/zhangdongzi/archive/2011/04/14/2016434.html 在androd手机中处理xml数据时很常见的事情,通常在不同平台传输数据的时候,我们就可能使用xml,xml是与平台无关的特性,被广泛运用于数据通信中,那么在android中如何解析xml文件数据呢? 通常有三种方式:DOM,SAX,PULL 在这一节中我们使用DOM方式来处理. DOM方式解析xml是先把xml文档都读到内存中,然后再用DOM API来访问

  • Android 中使用Pull解析XML文件

    解析XML文件是非常常用的功能,在Android客户端中,经常与服务器通信都需要xml文件的支持,我们这里介绍一个 简单的xml文件的解析,就是使用android中的pull方法进行解析.在java中,有dom解析和sax解析,这个pull解析有些类 似于sax解析,他也是一行一行的读取然后解析内容的方法. 首先看一下这个简单的xml文件 <?xml version="1.0" encoding="utf-8"?> <infos> <c

  • Android下Xml解析技术(3)之SAX解析Xml文件

    原文地址:http://blog.csdn.net/ichliebephone/article/details/5971533 Xml文件有许多解析方式,在学习J2EE中就学过很多,比如DOM,DOM4j,SAX,JDOM等等. 在Android中,比较常见的有SAX,DOM和Pull这三种解析方式.并且Android上对XML解析的支持是相当强大的,看一下 Android 中和 XML 解析相关的包: 1. android.sax 这是Android SDK提供的sax解析的包,因为可以对具体

  • 关于android单元测试结合SAX解析xml文件初步分析

    学android有一段时间了,最让我困惑的是项目老报错,一个Debug找半天很费时一直很苦恼.昨天晚上看了android单元测试资料.给大家分享下我学到的一点调试技巧,不要喷我.小弟刚接触android不久.首先单元测试(Junit)是由Erich Gamma和KentBeck编写的一个回归测试框架.Junit测试是程序员自己测试,即通常我们所说的白盒测试.目前版本主要分为3.x跟4.x.这里我用SAX解释XML的实例做个小测试.好了,废话不多说,直接写步骤吧. 1)首先在AndroidMani

  • Android中使用PULL方式解析XML文件深入介绍

    一.基本介绍 Android中极力推荐xmlpull方式解析xml. xmlpull不仅可用在Android上同样也适用于javase,但在javase环境中需自己获取xmlpull所依赖的类库,kxml2-2.3.0.jar,xmlpull_1_1_3_4c.jar. jar包下载网址 http://www.xmlpull.org/ http://kxml.sourceforge.net/ 二.例子 读取到xml的声明返回数字0 START_DOCUMENT; 读取到xml的结束返回数字1 E

Tags: