详解android使用SAX解析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时所用)。详细介绍如下表:

在上述四个接口中,最重要的就是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 localName , String qName) throws SAXException

//处理元素的字符内容,从参数中可以获得内容

public void characters(char[] ch , int start , int length) throws SAXException

这里再介绍下XMLReader中的方法。

//注册处理XML文档解析事件ContentHandler
public 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, String localName, String qName,
      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 localName, String qName)
      throws SAXException {
    // TODO Auto-generated method stub
    if(localName.equals("item")){
      RssFeed.addItem(RssItem);
      return;
    }
  }

  @Override
  public void characters(char[] ch, int start, 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);
  }
}

展示下运行结果:

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

(0)

相关推荐

  • 详解Android之解析XML文件三种方式(DOM,PULL,SAX)

    1.xml文件代码 <?xml version="1.0" encoding="UTF-8" ?> <%@ page language="java" contentType="text/xml; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core

  • Android编程使用sax解析xml数据的方法详解

    本文实例讲述了Android编程使用sax解析xml数据的方法.分享给大家供大家参考,具体如下: 随着技术的发展,现在的web已经和以前不同了.web已经逐渐像移动的方向倾斜,作为程序员的确应该拓展一下自己的知识层面.学习各方面的知识,今天就接着前几天的弄一下Android的xml解析,这次就使用sax的方式解析xml.下面就一步一步的来做吧. 1. 编写一个简单的xml <?xml version="1.0" encoding="UTF-8"?> &l

  • 基于Android XML解析与保存的实现

    解析XML文件:在Android平台上可以使用SAX.DOM和Android附带的pull解析器解析XML文件:pull解析器提供了各种事件,使用parser.next()方法进入下一个元素并触发相应事件,pull解析器产生的事件是一个数字,可以通过switch对感兴趣的事件进行处理:通过paser.nextText()方法可以获取下一个Text类型的节点的值:http://xmlpull.org/xmlpull-website/impls.shtml; 读取XMLXmlPullParser p

  • Android编程解析XML方法详解(SAX,DOM与PULL)

    本文实例讲述了Android编程解析XML方法.分享给大家供大家参考,具体如下: XML在各种开发中都广泛应用,Android也不例外.作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能.今天就由我向大家介绍一下在Android平台下几种常见的XML解析和创建的方法. 在Android中,常见的XML解析器分别为SAX解析器.DOM解析器和PULL解析器,下面,我将一一向大家详细介绍. SAX解析器: SAX(Simple API for XML)解析器是一种基于事

  • Android 创建与解析XML(五)——详解Dom4j方式

    1.Dom4j概述 dom4j is an easy to use, open source library for working with XML, XPath and XSLT on the Java platform using the Java Collections Framework and with full support for DOM, SAX and JAXP. dom4j官方网址:dom4j dom4j源码下载:dom4j download 本示例中,需要导入dom4j

  • Android创建与解析XML(二)——详解Dom方式

    1. Dom概述 Dom方式创建XML,应用了标准xml构造器 javax.xml.parsers.DocumentBuilder 来创建 XML 文档,需要导入以下内容 javax.xml.parsers javax.xml.parsers.DocumentBuilder javax.xml.parsers.DocumentBuilderFactory javax.xml.parsers.ParserConfigurationException; javax.xml.transform jav

  • Android中使用sax解析xml文件的方法

    SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于Android等移动设备. SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML 语法中的某部分,如果符合就会触发事件.所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口.下面是一些ContentHandler接口常用的方法: startDocument():当遇到文档的开头的时候,调用

  • Android 解析XML 文件的四种方法总结

    java解析xml文件四种方式 1.介绍 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在树中寻找特定信息.分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作.由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的.DOM以及广义的基于树的处理具有几个优点.首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改.它还可以

  • Android XML数据的三种解析方式

    本篇文章包含以下内容: XML数据的Dom解析      XML数据的Sax解析      XML数据的Pull解析      Activity中使用三种解析      Sax解析与Pull解析区别 三种解析方式的步骤: 1.在Assets文件夹中模拟创建XML数据 2.创建对应XML的Bean对象 3.开始解析 XML数据的Dom解析 DOM解析XML文件时,会将XML文件的所有内容读取到内存中(内存的消耗比较大),然后允许您使用DOM API遍历XML树.检索所需的数据 一.在Assets文

  • Android解析XML的三种方式SAX、Pull、Dom

    在android开发中,经常用到去解析xml文件,常见的解析xml的方式有一下三种:SAX.Pull.Dom解析方式.最近做了一个android版的CSDN阅读器,用到了其中的两种(sax,pull),本文对android解析xml的这三种方式进行一次总结. 今天解析的xml示例(channels.xml)如下: <?xml version="1.0" encoding="utf-8"?> <channel> <item id=&quo

  • Android创建与解析XML(三)——详解Sax方式

    1. Sax概述 SAX是一种占用内存少且解析速度快的解析器,它采用的是事件启动,不需要解析完整个文档,而是按照内容顺序看文档某个部分是否符合xml语法,如果符合就触发相应的事件,所谓的事件就是些回调方法(callback),这些方法 定义在ContentHandler中,下面是其主要方法: startDocument():当遇到文档的时候就触发这个事件 调用这个方法 可以在其中做些预处理工作,如:申请对象资源 endDocument():当结束文档的时候就触发这个事件 调用这个方法 可以在其中

  • Android 创建与解析XML(四)——详解Pull方式

     1.Pull概述 Android系统中和创建XML相关的包为org.xmlpull.v1,在这个包中不仅提供了用于创建XML的 XmlSerializer,还提供了用来解析XML的Pull方式解析器 XmlPullParser XmlSerializer没有像XmlPullParser那样提取XML事件,而是把它们推出到数据流OutputStream或Writer中. XmlSerializer提供了很直观的API,即使用startDocument开始文档,endDocument结束文档,st

随机推荐