详解android使用SAX解析XML文件

详解android使用SAX解析XML文件,第1张

概述解析XML的方式有很多种,大家比较熟悉的可能就是DOM解析。DOM(文件对象模型)解析:解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以根据DOM接口来 *** 作这个树结构了。

解析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 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,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 qname)      throws SAXException {    // Todo auto-generated method stub    if(localname.equals("item")){      RSSFeed.addItem(RSSItem);      return;    }  }    @OverrIDe  public voID characters(char[] ch,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);  }}

展示下运行结果:


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的详解android使用SAX解析XML文件全部内容,希望文章能够帮你解决详解android使用SAX解析XML文件所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1147763.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存