Android之XML文件解析

转载请注明出处:http://blog.csdn.net/joker_ya/article/details/38778971

OK!今天給带来的是Android对XML文件的解析方法。对于XML文件,有三种解析方法。它们分别是:SAX解析,DOM解析和PULL解析。下面我们就一个一个的来分析。

1.SAX解析

含义:SAX(simple API for XML)是一种XML解析的替代方法。相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就是操作复杂。

原理:SAX,它既是一个接口,也是一个软件包.但作为接口,SAX是事件驱动型XML解析的一个标准接口不会改变 SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。

大多数SAX都会产生以下类型的事件:

1).在文档的开始和结束时触发文档处理事件。

2).在文档内每一XML元素接受解析的前后触发元素事件。

3).任何元数据通常由单独的事件处理

4).在处理文档的DTD或Schema时产生DTD或Schema事件。

5).产生错误事件用来通知主机应用程序解析错误。

2.DOM解析

DOM(Document Object Model)是一种用于XML 文档的对象模型,可用于直接访问XML文档的各个部分。文档都被组织成了数据结构上的树的形式,DOM解析以后可以将这个文档读到内存中并且以树的形式被组织。DOM比SAX更容易掌握,因为它没有涉及回调和复杂的状态管理。然而,DOM的实现常常将所有XML节点保持在内存中,这使处理较大的文档变得效率低下。尤其是对于小内存的手机而言。

通过DOM将XML文档作为一个树形结构,这种树形结构也被称为节点树,如下图所示。


3.PULL解析

PULL解析器的运行方式与SAX解析器相似。它提供了类似的事件,如开始元素和结束元素事件。使用parser.next()可以进入下一个元素并触发相应的事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行选择,然后进行相应的处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型元素的值。

和SAX不同的是,SAX的事件驱动是回调相应的方法,我们需要提供回调的方法,而后在SAX内部自动调用相应的方法。而PULL解析器并没有强制要求我们提供触发的方法。因为触发的事件并不是一个方法,而是一个数字。至于触发的事件要不要处理,就由程序员自己决定了。

好了,说了那么多了,都是一些含义、原理什么的。怪难理解的!那么,接下来就写一个Demo来帮助大家理解吧!

打开工程新建名为AnalysisXMLDemo的项目,目录结构如下:


首先给出我们要解析的XML文件persons.xml

<span style="font-size:18px;"><span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
<persons>
    <person id="1">
        <name>张三</name>
        <age>20</age>
    </person>
    <person id="2">
        <name>李四</name>
        <age>21</age>
    </person>
    <person id="3">
        <name>王五</name>
        <age>22</age>
    </person>
    <person id="4">
        <name>麻六</name>
        <age>23</age>
    </person>    
</persons></span></span>

然后我们新建一个Person.java类来接收解析的数据

<span style="font-size:18px;"><span style="font-size:18px;">package com.example.domain;
/**
 * 创建一个Person类
 * @author Joker_Ya
 *
 */
public class Person {
	private int id;
	private String name;
	private short age;	
	/**
	 * 构造函数
	 */
	public Person() {
	}
	public Person(String name, short age) {
		this.name = name;
		this.age = age;
	}
	public Person(int id, String name, short age) {
		this.id = id;
		this.name = name;
		this.age = age;
	}
	/**
	 * 变量的set和get方法	 
	 */
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public short getAge() {
		return age;
	}
	public void setAge(short age) {
		this.age = age;
	}
	/**
	 * toString方法
	 * @return 
	 */
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
	}		
}
</span></span>

接下来就是编写SAX,DOM和PULL三种解析方法的解析代码了:

首先是SAX解析的代码SAXforHandler.java:

<span style="font-size:18px;"><span style="font-size:18px;">package com.example.analysisutils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

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

import android.util.Log;

import com.example.domain.Person;

/**
 * 新建SAXforHandler继承DefaultHandler,
 * 而DefaultHandler是实现了ContenHandler的接口,提供了相应的事件方法
 * 
 * @author Joker_Ya
 * 
 */
public class SAXforHandler extends DefaultHandler {

	private static final String TAG = "SAXforHandler";
	private List<Person> persons;
	private String perTag;// 记录前一个标签的名称
	private Person person;// 记录当前Person

	public List<Person> getPersons() {
		return persons;
	}

	/**
	 * 对传入的InputStream流进行SAX解析并返回结果
	 * 
	 * @param inStream
	 *            InputStream流
	 * @return 返回解析到的Person的list列表
	 * @throws Exception
	 *             抛出异常
	 */
	public static List<Person> sax_XML(InputStream inStream) throws Exception {
		SAXforHandler handler = new SAXforHandler();
		SAXParserFactory factory = SAXParserFactory.newInstance();
		SAXParser parser = factory.newSAXParser();
		parser.parse(inStream, handler);
		List<Person> list = handler.getPersons();
		inStream.close();
		return list;
	}

	/**
	 * 通知应用程序文档的开始 适合在此事件中触发初始化行为,
	 */
	@Override
	public void startDocument() throws SAXException {
		// TODO Auto-generated method stub
		persons = new ArrayList<Person>();
		// Log.v(TAG, "***startDocument()***");
	}

	/**
	 * 通知应用程序元素的开始,属性作为Attributes参数传递
	 * 
	 * @param uri
	 *            命名空间
	 * @param localName
	 *            标签名称
	 * @param qName
	 *            带命名空间的标签名
	 * @param attributes
	 *            存放该标签的所有属性
	 */
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		// TODO Auto-generated method stub
		if ("person".equals(localName)) {
			for (int i = 0; i < attributes.getLength(); i++) {
				// Log.v(TAG,
				// "attributeName:"+attributes.getLocalName(i)+"_attributeValue:"+attributes.getValue(i));
				person = new Person();
				person.setId(Integer.valueOf(attributes.getValue(i)));
			}
		}
		perTag = localName;
		// Log.v(TAG, qName+"***startElement()***");
	}

	/**
	 * 当语法分析器在元素中发现文本(已经解析过的字符数据)时,characters()会被应用程序触发
	 * 
	 * @param ch
	 *            当前读取到的TextNode字节数组
	 * @param start
	 *            字节开始的位置
	 * @param length
	 *            当前TextNode的长度
	 */
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		// TODO Auto-generated method stub
		String data = new String(ch, start, length).trim();
		if (!"".equals(data.trim())) {
			Log.v(TAG, "content:" + data.trim());
		}
		if ("name".equals(perTag)) {
			person.setName(data);
		} else if ("age".equals(perTag)) {
			person.setAge(new Short(data));
		}
	}

	/**
	 * 通知应用程序元素的结束。
	 */
	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		// TODO Auto-generated method stub
		// Log.v(TAG, qName+"***endElement()***");
		if ("person".equals(localName) && person != null) {
			persons.add(person);
			person = null;
		}
		perTag = null;
	}

	/**
	 * 通知应用程序文档的结束
	 */
	@Override
	public void endDocument() throws SAXException {
		// TODO Auto-generated method stub
		// Log.v(TAG, "***endDocument()***");
	}

}
</span></span>

然后是DOM解析的代码DomService.java:

<span style="font-size:18px;"><span style="font-size:18px;">package com.example.analysisutils;

import java.io.InputStream;
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.Node;
import org.w3c.dom.NodeList;

import com.example.domain.Person;
/**
 * 	DOM解析核心代码
 * @author Joker_Ya
 *	整个解析过程我们可以参照上文中的节点树图,获得各个节点的顺序是严格按照树状结构的。
 */
public class DomService {
	public static List<Person> readXml(InputStream inStream) throws Exception {
		List<Person> persons = new ArrayList<Person>();
		//创建DocumentBuilderFactory,该对象将创建DocumentBuilder
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		//创建DocumentBuilder,DocumentBuilder将实际进行解析以创建Document对象
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.parse(inStream);
		Element root = document.getDocumentElement();
		NodeList nodes = root.getElementsByTagName("person");
		for (int i = 0; i < nodes.getLength(); i++) {
			Element personElement = (Element) nodes.item(i);
			Person person = new Person();
			person.setId(Integer.parseInt((personElement.getAttribute("id"))));
			NodeList childNodes = personElement.getChildNodes();
			for (int y = 0; y < childNodes.getLength(); y++) {
				Node childNode = childNodes.item(y);
				if (childNode.getNodeType() == Node.ELEMENT_NODE) {
					Element childElement = (Element) childNode;
					if ("name".equals(childElement.getNodeName())) {
						person.setName(childElement.getFirstChild()
								.getNodeValue());
					} else if ("age".equals(childElement.getNodeName())) {
						person.setAge(new Short(childElement.getFirstChild()
								.getNodeValue()));
					}
				}
			}
			persons.add(person);
		}
		return persons;
	}
}
</span></span>

最后是PULL解析的代码PullService.java

<span style="font-size:18px;"><span style="font-size:18px;">package com.example.analysisutils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import android.util.Xml;

import com.example.domain.Person;
/**
 * PULL解析核心代码
 * @author Joker_Ya
 *
 */
public class PullService {
	public static List<Person> readXml(InputStream inStream) throws Exception {
		List<Person> persons = null;
		XmlPullParser parser = Xml.newPullParser();
		parser.setInput(inStream, "UTF-8");
		//得到PULL解析器的事件,其返回值是int类型的
		int eventCode = parser.getEventType();
		Person person = null;
		// 用switch循环,如果获得的事件码是文档结束,那么结束解析(parser.next()来触发下一事件)
		while (eventCode != XmlPullParser.END_DOCUMENT) {
			switch (eventCode) {
			case XmlPullParser.START_DOCUMENT:// 文档开始事件
				persons = new ArrayList<Person>();
				break;
			case XmlPullParser.START_TAG:// 开始元素
				// 判断当前元素是否是需要检索的元素
				if ("person".equals(parser.getName())) {
					person = new Person();
					person.setId(Integer.parseInt(parser.getAttributeValue(0)));
				} else if (person != null) {
					if ("name".equals(parser.getName())) {
						person.setName(parser.nextText());
					} else if ("age".equals(parser.getName())) {
						person.setAge(new Short(parser.nextText()));
					}
				}
				break;
			case XmlPullParser.END_TAG:// 结束元素
				if ("person".equals(parser.getName()) && person != null) {
					persons.add(person);
					person = null;
				}
				break;
			default:
				break;
			}
			//下一个事件,是parser中最重要的方法
			eventCode = parser.next();
		}
		return persons;
	}
}
</span></span>

 至此关于SAX解析,DOM解析和PULL解析的核心代码全部给出来了。其实弄懂了它们的原理和解析时的顺序就很容易了。

下面就是界面activity_main.xml:

<span style="font-size:18px;"><span style="font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >
	<LinearLayout 
	    android:layout_width="fill_parent"
	    android:layout_height="fill_parent"
	    android:orientation="vertical"
	    >
    <Button 
        android:id="@+id/sax_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SAX解析XML"
        />
    <Button 
        android:id="@+id/dom_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="DOM解析XML"
        />
    <Button 
        android:id="@+id/pull_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="PULL解析XML"
        />
    <TextView 
        android:id="@+id/showtext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"        
        />
    <ListView 
        android:id="@+id/listview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"       
        ></ListView>
    </LinearLayout>
</RelativeLayout></span></span>

接下来就是MainActivity.java:

<span style="font-size:18px;"><span style="font-size:18px;">package com.example.analysisxmldemo;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.example.analysisutils.DomService;
import com.example.analysisutils.PullService;
import com.example.analysisutils.SAXforHandler;
import com.example.domain.Person;

import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

/**
 * 
 * @author Joker_Ya
 * 
 */
public class MainActivity extends Activity implements OnClickListener {

	private Button sax_button;
	private Button dom_button;
	private Button pull_button;
	
	private TextView showtext;
	private ListView listView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		sax_button = (Button) findViewById(R.id.sax_button);
		dom_button = (Button) findViewById(R.id.dom_button);
		pull_button = (Button) findViewById(R.id.pull_button);
		showtext = (TextView) findViewById(R.id.showtext);
		listView = (ListView) findViewById(R.id.listview);
		
		sax_button.setOnClickListener(this);
		dom_button.setOnClickListener(this);
		pull_button.setOnClickListener(this);
	}

	/**
	 * 按钮的点击事件判断和处理。
	 */
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.sax_button://点击了“SAX解析XML”按钮
			try {
				// 用类装载器得到persons.xml文件的输入流
				InputStream is = MainActivity.class.getClassLoader()
						.getResourceAsStream("persons.xml");
				List<Person> persons;
				persons = SAXforHandler.sax_XML(is);
				List<Map<String, String>> lists = new ArrayList<Map<String, String>>();
				Map<String, String> hasmap;
				String[] Strpersons = new String[persons.size()];
				for (int i = 0; i < persons.size(); i++) {
					hasmap = new HashMap<String, String>();
					hasmap.put("number", Strpersons[i] = persons.get(i)
							.toString() + "by SAX");
					lists.add(hasmap);
				}
				showtext.setText("使用SAX解析persons.xml");
				//新建一个SimpleAdapter适配器
				SimpleAdapter adapter = new SimpleAdapter(this, lists,
						android.R.layout.simple_list_item_1,
						new String[] { "number" },
						new int[] { android.R.id.text1 });
				//将解析的数据在listView中显示
				listView.setAdapter(adapter);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			break;
		case R.id.dom_button://点击了“DOM解析XML”按钮
			try {
				InputStream is = MainActivity.class.getClassLoader()
						.getResourceAsStream("persons.xml");
				List<Person> persons;
				persons = DomService.readXml(is);
				String[] Strpersons = new String[persons.size()];
				for (int i = 0; i < persons.size(); i++) {
					Strpersons[i] = persons.get(i).toString() + "by DOM";
				}
				showtext.setText("使用DOM解析persons.xml");
				//新建一个ArrayAdapter适配器
				ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
						android.R.layout.simple_list_item_1, Strpersons);				
				listView.setAdapter(adapter);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			break;
		case R.id.pull_button://点击了“PULL解析XML”按钮
			try {
				InputStream is = MainActivity.class.getClassLoader()
						.getResourceAsStream("persons.xml");
				List<Person> persons;
				persons = PullService.readXml(is);
				String[] Strpersons = new String[persons.size()];
				for (int i = 0; i < persons.size(); i++) {
					Strpersons[i] = persons.get(i).toString() + "by PULL";
				}
				showtext.setText("使用PULL解析persons.xml");
				ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
						android.R.layout.simple_list_item_1, Strpersons);
				listView.setAdapter(adapter);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			break;
		default:
			break;
		}
	}
}
</span></span>

在这里要说明一点,就是使用SAX解析得到返回的数据并用ListView显示时。如果用ArrayAdapter适配器来绑定数据时,程序会报错。因此SAX解析那里使用了SimpleAdapter适配器来绑定数据。至于为什么会报错,个人觉得是适配器的问题,如果有哪位大神知道的麻烦告诉我一下。感谢。

最后的最后就是给出结果图了:

首先是程序初始运行图:

点击SAX解析XML按钮图:

点击DOM解析XML按钮图:


点击PULL解析XML按钮图:


噢,还有最后,那就是源代码下载地址

AnalysisXMLDemo


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值