一、Android开发中三种主要的XML解析方法


在平时的工作和学习中,我们经常需要在android项目中解析XML文件,android为我们提供了三种解析XML的方法,分别是Sax解析、Pull解析和Dom解析,下面简要介绍下这三种解析方法:


SAX解析器:

SAX(Simple API for XML)解析器是一种

基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。

SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。



DOM解析器:

DOM是

基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。

由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。



PULL解析器:

PULL解析器的运行方式和SAX类似,都是

基于事件的模式。不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。 PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。




二、三种解析方法的代码怎么写


先看要解析的XML文件格式:


<city quName="黑龙江" pyName="heilongjiang" cityname="哈尔滨" state1="13" state2="13" stateDetailed="阵雪" tem1="-13" tem2="-19" windState="北风4-5级转3-4级"/>

这里只放了一个标签,整个xml文件的内容就是由很多这个标签组成的,限于篇幅,这里就不贴上全部文件内容了


SAX解析:



实现Sax解析我们需要继承类DefaultHandler,通过复写其中的characters(), endDocument(), endElement(), startDocument(), startElement()等方法,从而解析出XML文件中的节点信息,首先看MyContentHandler.java,该类继承了DefaultHandler,代码如下:



package com.example.xmlparsetest.sax;

import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.example.xmlparsetest.adapter.MyListAdapter;
import com.example.xmlparsetest.bean.CityBean;

import android.content.Context;
import android.util.Log;
import android.widget.ListView;

public class MyContentHandler extends DefaultHandler {
	private String tag = null;
	private List<CityBean> cityList = new ArrayList<CityBean>();
	private ListView listView;
	private Context context;
	private long startTime;
	private long endTime;
	
	/**构造方法,传入上下文context和ListView,解析文档结束后在ListView上显示解析后的数据*/
	public MyContentHandler(Context context, ListView listView){
		this.context = context;
		this.listView = listView;
	}

	/**重要的方法之一,用于获取节点中的数据*/
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		super.characters(ch, start, length);
	}
	
	public List<CityBean> getList(){
		return cityList;
	}
	
	public long getTime(){
		return endTime - startTime;
	}

	/**重要方法之一*/
	@Override
	public void endDocument() throws SAXException {
		super.endDocument();
		endTime = System.currentTimeMillis();
		//解析到文档结束,将数据显示到ListView上
		listView.setAdapter(new MyListAdapter(context, cityList));
	}

	/**重要方法之一*/
	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		super.endElement(uri, localName, qName);
		tag = null;
	}

	/**重要方法之一*/
	@Override
	public void startDocument() throws SAXException {
		super.startDocument();
		startTime = System.currentTimeMillis();
		Log.e("yubo", "startDocument");
	}

	/**重要方法之一*/
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		super.startElement(uri, localName, qName, attributes);
		//localName是节点名称
		tag = localName;
		//匹配到XML文件中的city节点
		if("city".equals(tag)){
			CityBean bean = new CityBean();
			//把节点中的属性取出来放到bean中
			bean.setQuName(attributes.getValue("quName"));
			bean.setPyName(attributes.getValue("pyName"));
			bean.setCityname(attributes.getValue("cityname"));
			bean.setState1(attributes.getValue("state1"));
			bean.setState2(attributes.getValue("state2"));
			bean.setStateDetailed(attributes.getValue("stateDetailed"));
			bean.setTem1(attributes.getValue("tem1"));
			bean.setTem2(attributes.getValue("tem2"));
			bean.setWindState(attributes.getValue("windState"));
			cityList.add(bean);
		}
	}

	
}

上面的代码有些地方做了注释,带有@Override的方法都是复写过的,是Sax解析XML必不可少的方法,下面看上面写的DefaultHandler类怎么用,代码如下:



package com.example.xmlparsetest.dom;

import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ListView;

import com.example.xmlparsetest.R;
import com.example.xmlparsetest.adapter.MyListAdapter;
import com.example.xmlparsetest.bean.CityBean;
import com.example.xmlparsetest.utils.FileUtils;

public class TestDomActivity extends Activity {
	private ListView listView;
	private long startTime;
	private long endTime;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_list);
		
		listView = (ListView) findViewById(R.id.listview);
		parse();
	}
	
	/**解析XML的主要方法*/
	private void parse(){
		List<CityBean> cityList = new ArrayList<CityBean>();
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(FileUtils.getFileInputStream(this));
			startTime = System.currentTimeMillis();
			//得到文档的根节点
			Element root = doc.getDocumentElement();
			//从根节点中选择出节点名为city的子节点,构成一个节点list
			NodeList nodeList = root.getElementsByTagName("city");
			//通过循环将每个city节点中的数据解析出来
			for(int i = 0; i < nodeList.getLength(); i++){
				CityBean bean = new CityBean();
				//得到第i个city节点
				Element element = (Element)nodeList.item(i);
				//获取city节点中的属性值
				String quName = element.getAttribute("quName");
				String pyName = element.getAttribute("pyName");
				String cityname = element.getAttribute("cityname");
				String state1 = element.getAttribute("state1");
				String state2 = element.getAttribute("state2");
				String stateDetailed = element.getAttribute("stateDetailed");
				String tem1 = element.getAttribute("tem1");
				String tem2 = element.getAttribute("tem2");
				String windState = element.getAttribute("windState");
				bean.setQuName(quName);
				bean.setPyName(pyName);
				bean.setCityname(cityname);
				bean.setState1(state1);
				bean.setState2(state2);
				bean.setStateDetailed(stateDetailed);
				bean.setTem1(tem1);
				bean.setTem2(tem2);
				bean.setWindState(windState);
				cityList.add(bean);
			}
			//计算解析用时并返回给上一个activity
			endTime = System.currentTimeMillis();
			Intent intent = new Intent();
			intent.putExtra("time", endTime - startTime);
			setResult(301, intent);
			//在ListView上显示数据
			MyListAdapter adapter = new MyListAdapter(this, cityList);
			listView.setAdapter(adapter);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

DOM解析:



package com.example.xmlparsetest.dom;

import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ListView;

import com.example.xmlparsetest.R;
import com.example.xmlparsetest.adapter.MyListAdapter;
import com.example.xmlparsetest.bean.CityBean;
import com.example.xmlparsetest.utils.FileUtils;

public class TestDomActivity extends Activity {
	private ListView listView;
	private long startTime;
	private long endTime;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_list);
		
		listView = (ListView) findViewById(R.id.listview);
		parse();
	}
	
	/**解析XML的主要方法*/
	private void parse(){
		List<CityBean> cityList = new ArrayList<CityBean>();
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(FileUtils.getFileInputStream(this));
			startTime = System.currentTimeMillis();
			//得到文档的根节点
			Element root = doc.getDocumentElement();
			//从根节点中选择出节点名为city的子节点,构成一个节点list
			NodeList nodeList = root.getElementsByTagName("city");
			//通过循环将每个city节点中的数据解析出来
			for(int i = 0; i < nodeList.getLength(); i++){
				CityBean bean = new CityBean();
				//得到第i个city节点
				Element element = (Element)nodeList.item(i);
				//获取city节点中的属性值
				String quName = element.getAttribute("quName");
				String pyName = element.getAttribute("pyName");
				String cityname = element.getAttribute("cityname");
				String state1 = element.getAttribute("state1");
				String state2 = element.getAttribute("state2");
				String stateDetailed = element.getAttribute("stateDetailed");
				String tem1 = element.getAttribute("tem1");
				String tem2 = element.getAttribute("tem2");
				String windState = element.getAttribute("windState");
				bean.setQuName(quName);
				bean.setPyName(pyName);
				bean.setCityname(cityname);
				bean.setState1(state1);
				bean.setState2(state2);
				bean.setStateDetailed(stateDetailed);
				bean.setTem1(tem1);
				bean.setTem2(tem2);
				bean.setWindState(windState);
				cityList.add(bean);
			}
			//计算解析用时并返回给上一个activity
			endTime = System.currentTimeMillis();
			Intent intent = new Intent();
			intent.putExtra("time", endTime - startTime);
			setResult(301, intent);
			//在ListView上显示数据
			MyListAdapter adapter = new MyListAdapter(this, cityList);
			listView.setAdapter(adapter);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}



PULL解析:



pull解析的代码也不复杂,直接上代码:



package com.example.xmlparsetest.pull;

import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Xml;
import android.widget.ListView;

import com.example.xmlparsetest.R;
import com.example.xmlparsetest.adapter.MyListAdapter;
import com.example.xmlparsetest.bean.CityBean;
import com.example.xmlparsetest.utils.FileUtils;

public class TestPullActivity extends Activity {
	private ListView listView;
	private long startTime;
	private long endTime;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_list);
		
		listView = (ListView) findViewById(R.id.listview);
		parse();
	}
	
	private void parse(){
		List<CityBean> cityList = new ArrayList<CityBean>();
		try {
			XmlPullParser parser = Xml.newPullParser();
			parser.setInput(FileUtils.getFileInputStream(this), "UTF-8");
			//获取事件类型
			int eventType = parser.getEventType();
			//根据事件类型做不同的处理,循环条件是没到文件结束
			while(eventType != XmlPullParser.END_DOCUMENT){
				switch(eventType){
				//开始解析文档
				case XmlPullParser.START_DOCUMENT:
					startTime = System.currentTimeMillis();
					break;
				//开始一个tag标签
				case XmlPullParser.START_TAG:
					if("city".equals(parser.getName())){
						String quName = parser.getAttributeValue(null, "quName");
						String pyName = parser.getAttributeValue(null, "pyName");
						String cityname = parser.getAttributeValue(null, "cityname");
						String state1 = parser.getAttributeValue(null, "state1");
						String state2 = parser.getAttributeValue(null, "state2");
						String stateDetailed = parser.getAttributeValue(null, "stateDetailed");
						String tem1 = parser.getAttributeValue(null, "tem1");
						String tem2 = parser.getAttributeValue(null, "tem2");
						String windState = parser.getAttributeValue(null, "windState");
						CityBean bean = new CityBean();
						bean.setQuName(quName);
						bean.setPyName(pyName);
						bean.setCityname(cityname);
						bean.setState1(state1);
						bean.setState2(state2);
						bean.setStateDetailed(stateDetailed);
						bean.setTem1(tem1);
						bean.setTem2(tem2);
						bean.setWindState(windState);
						cityList.add(bean);
					}
					break;
				}
				eventType = parser.next();
			}
			//计算解析事件
			endTime = System.currentTimeMillis();
			Intent intent = new Intent();
			intent.putExtra("time", endTime - startTime);
			setResult(201, intent);
		} catch (Exception e) {
			e.printStackTrace();
		}
		//在ListView上显示数据
		MyListAdapter adapter = new MyListAdapter(this, cityList);
		listView.setAdapter(adapter);
	}
}

可以看到,pull解析类似Sax解析,都有开始文档,开始标签,结束标签,结束文档的事件和对应的处理,不同的地方是,Sax解析已经将事件处理接口写好了,我们写好对应事件的处理代码就行,而pull解析则需要我们自己捕获相应的事件并写处理事件的代码。





下面上两张程序运行时截图:(这里的解析用时不能看出三种解析方式的好坏,毕竟文档的大小有大有小,在平时的开发中,要选择合适的解析方法)




android xml 等分 android xml解析方式_xml解析

android xml 等分 android xml解析方式_sax_02

三、一个小小的总结


作为与服务器端交互的数据格式,XML和JSON是平时开发中用得比较多的两种,我个人觉得JSON的解析更简单一些,XML稍微复杂了点,不过这两种数据格式的解析我们都要掌握好嘛,下一篇再讲JSON数据的解析方法。这一篇的源码在这里: 点击下载