【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的实现。


下面是XML文件:




	
	
		0001
		m1.mp3
		5746816				
		m1.lrc
		1778
	
	
	
		0002
    m2.mp3
		5420198				
		m2.lrc
		1598
	
	

添加一个实体类,这样我们就可以把解析出来的信息放到实体类里面,然后直接操作实体类就可以了

Mp3Info.java

package android.model;

public class Mp3Info {

	private String id;
	private String mp3Name;
	private String mp3Size;
	private String lrcName;
	private String lrcSize;
	
	public Mp3Info() {
		super();
	}
	
	public Mp3Info(String id, String mp3Name, String mp3Size, String lrcName,
			String lrcSize) {
		super();
		this.id = id;
		this.mp3Name = mp3Name;
		this.mp3Size = mp3Size;
		this.lrcName = lrcName;
		this.lrcSize = lrcSize;
	}
	
	@Override
	public String toString() {
		return "Mp3Info [id=" + id + ", mp3Name=" + mp3Name + ", mp3Size="
				+ mp3Size + ", lrcName=" + lrcName + ", lrcSize=" + lrcSize
				+ "]";
	}

	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getMp3Name() {
		return mp3Name;
	}
	public void setMp3Name(String mp3Name) {
		this.mp3Name = mp3Name;
	}
	public String getMp3Size() {
		return mp3Size;
	}
	public void setMp3Size(String mp3Size) {
		this.mp3Size = mp3Size;
	}
	public String getLrcName() {
		return lrcName;
	}
	public void setLrcName(String lrcName) {
		this.lrcName = lrcName;
	}
	public String getLrcSize() {
		return lrcSize;
	}
	public void setLrcSize(String lrcSize) {
		this.lrcSize = lrcSize;
	}
		
}

下面就是最最重要的地方了,建立自己的ContentHandler.看下面的代码:

Mp3ListContentHandler:

package android.xml;

import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.model.Mp3Info;

public class Mp3ListContentHandler extends DefaultHandler{
	
	private List infos=null;
	private Mp3Info mp3Info=null;
	private String tagName=null;
	
	public Mp3ListContentHandler(List infos) {
		super();
		this.infos = infos;
	}

	public List getInfos() {
		return infos;
	}

	public void setInfos(List infos) {
		this.infos = infos;
	}


	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		
		//System.out.println("-------characters------");
		String temp=new String(ch, start, length);
		if(tagName.equals("id")){
			mp3Info.setId(temp);
		}
		else if(tagName.equals("mp3.name")){
			mp3Info.setMp3Name(temp);
		}
		else if(tagName.equals("mp3.size")){
			mp3Info.setMp3Size(temp);
		}
		else if(tagName.equals("lrc.name")){
			mp3Info.setLrcName(temp);
		}
		else if(tagName.equals("lrc.size")){
			mp3Info.setLrcSize(temp);			
		}
	}

	@Override
	public void endDocument() throws SAXException {
		//System.out.println("------endDocument------");
	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		//System.out.println("---------endElement----------");
		if(qName.equals("resource")){
			infos.add(mp3Info);
		}
		tagName="";
	}

	@Override
	public void startDocument() throws SAXException {
		// TODO Auto-generated method stub
		super.startDocument();
		//System.out.println("---------startDocument--------");
	}

	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		this.tagName=localName;
		//System.out.println("--------startElement-------");
		if(tagName.equals("resource")){
			mp3Info=new Mp3Info();
		}
	}
	
}

就上面的代码分析,实现一个ContentHandler一般要一下几个步骤:

1、声明一个类,继承DefaultHandler。DefaultHandler是一个基类,这个类里面简单实现了一个ContentHandler。我们只需要重写里面的方法即可。

2、重写 startDocument() 和 endDocument(),一般解析将正式解析之前的一些初始化工资放到startDocument()里面,收尾的工作放到endDocument()里面。

3、重写startElement(),XML解析器遇到XML里面的tag时就会调用这个函数。经常在这个函数内是通过localName俩进行判断而操作一些数据。

4、重写characters()方法,这是一个回调方法。解析器执行完startElement()后,解析完节点的内容后就会执行这个方法,并且参数ch[]就是节点的内容。

5、重写endElement()方法,这个方法与startElement()相对应,解析完一个tag节点后,执行这个方法。再找个例子中,如果解析一个item结束,就将RSSIiem添加到RSSFeed中



最后我们实现一个activity来展现解析的结果:

package android.test;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import android.app.ListActivity;
import android.download.HttpDownloader;
import android.model.Mp3Info;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.xml.Mp3ListContentHandler;

public class Mp3ListActivity extends ListActivity {
	private static final int UPDATE=1;
	private static final int ABOUT=2;
	/*
	 * 当用户点击MENU按钮时,调用该方法,可以在这个方法中放入自己的控件 
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		menu.add(0, UPDATE, 1, R.string.mp3list_update);
		menu.add(0, ABOUT, 2, R.string.mp3list_about);
		return super.onCreateOptionsMenu(menu);				
	}
	
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
                
    }
	
	//处理按钮的函数,当用户点击menu弹出的按钮时会触发此函数
    @Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
    	//System.out.println("item id------>"+item.getItemId());
		if(item.getItemId()==UPDATE){
			//用户点击了更新列表按钮
			String xml=downloadXML("http://172.23.10.234:8080/mp3/resources.xml");
			parse(xml);
		}
		else if(item.getItemId()==ABOUT){
			//用户点击了关于按钮
		}
    	return super.onOptionsItemSelected(item);
	}

    public String downloadXML(String urlStr){
    	HttpDownloader httpDownloader=new HttpDownloader();
		String result=httpDownloader.download(urlStr);
    	return result;
    }
    
    private List parse(String xmlStr){
    	SAXParserFactory saxParserFactory=SAXParserFactory.newInstance();
		List infos=new ArrayList();
    	try {
			//SAX解析XML文件固定写法
    		XMLReader xmlReader=saxParserFactory.newSAXParser().getXMLReader();
			//为XMLReader设置内容处理器
    		Mp3ListContentHandler mp3ListContentHandler=new Mp3ListContentHandler(infos);
			xmlReader.setContentHandler(mp3ListContentHandler);
			//开始解析文件
			xmlReader.parse(new InputSource(new StringReader(xmlStr)));
			for (Iterator iterator = infos.iterator(); iterator.hasNext();) {
				Mp3Info mp3Info = (Mp3Info) iterator.next();
				System.out.println(mp3Info);
			}			
    	} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }

}




 
  
 
  
 
  
 
 

你可能感兴趣的:(【android】SAX解析XML文件)