前序:XML是可扩展性标记语言,可以自己定义标签.在android中处理xml数据很常见,通常在不同平台传输数据的时候,就会用到xml,xml是与平台无关的特性,被广泛运用于数据通信中.
android中解析xml数据通常有三种方式:DOM,SAX,PULL.下面进行三种方式的介绍:
新建项目:XmlParserDemo
项目目的:解析出文件中的student对象。在Activity程序中通过三个Button分别跳转到三种解析方式中用ListView显示所有学生的对象。
DOM解析xml
DOM是Document Object Model的缩写,即文档对象模型.DOM解析器是通过将XML文档解析成树状模型并将其放入内存来完成解析工作的,而后对文档的操作都是在这个树状模型上完成.这个在内存中的文档是实际文档大小的几倍.
好处是结构清晰,操作方便,坏处是耗费系统资源.
要解析的xml文件:student.xml置于asset/xml目录中
<?xml version="1.0" encoding="utf-8"?>
<students>
<student id="8">
<name>张三</name>
<age value="20"></age>
</student>
<student id="9">
<name>李四</name>
<age value="21"></age>
</student>
<student id="10">
<name>王五</name>
<age value="22"></age>
</student>
</students>
|
Student类:
package com.bawei.xml;
publicclass Student {
privateint mId;
private String mName;
privateint mAge;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(int mId, String mName, int mAge) {
super();
this.mId = mId;
this.mName = mName;
this.mAge = mAge;
}
publicint getId() {
return mId;
}
publicvoid setId(int mId) {
this.mId = mId;
}
public String getName() {
return mName;
}
publicvoid setName(String mName) {
this.mName = mName;
}
publicint getAge() {
return mAge;
}
publicvoid setAge(int mAge) {
this.mAge = mAge;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append("id: ").append(mId).append(", name: " ).append(mName).append(", age: " )
.append(mAge);
return str.toString();
}
}
|
至此,准备工作已经完成。下面开始进行解析。
DOM解析xml所需的三个包:
import javax.xml.parsers.DocumentBuilder; //包含DOM解析器SAX解析器的具体实现
import javax.xml.parsers.DocumentBuilderFactory;//定义了W3C制定的DOM接口
|
第一步:创建DocumentBuliderFactory的实例
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
DocumentBulider可以理解为一个xml文件的解析器。这个解析器需要通过DocumentBuilderFactory调用newInstance()方法获得。
第二步:实例化一个解析器DocumentBuilder的对象
DocumentBuilder db = dbf.newDocumentBuilder();
|
得到了解析器的对象,就可以加载要解析的xml文件进行解析
第三步:加载一个xml文件:
Document doc = db.parse(this.getAssets().open("xml/students.xml"));
|
Document 是一个xml文件的对象。通过解析器DocumentBuilder中的parse()方法进行加载。
注意:着重注意的是在assets中读取文件的方法
parse()方法可以加载xml文件为Document实例化对象。其中可以用一下三种方式:
·输入流:parse(InputStream is)
·Uri:parse(String uri)
·输入流资源:parse(InputSource is)
第四步:遍历文件中的所有节点:
//获取Document根节点
Element root = doc.getDocumentElement();
//拿到某个标签的节点列表
NodeList nodeList = root.getElementsByTagName("student");
int length = nodeList.getLength();
Student student = null;
//遍历节点列表
for(int i=0; i<length; i++){
student = new Student();
Element studentNode = (Element)nodeList.item(i); student.setId(Integer.valueOf(studentNode.getAttribute("id")));
//拿到<student>标签的子节点列表
NodeList childNode = studentNode.getChildNodes();
int childNodeLength = childNode.getLength();
//遍历子节点列表
for(int j=0; j<childNodeLength; j++){
Node node = childNode.item(j);
if(node.getNodeType()==Node.ELEMENT_NODE){
Element)node;
if("name".equals(element.getNodeName())){
student.setName(element.getFirstChild().getNodeValue());
}elseif("age".equals(element.getNodeName())){
student.setAge(Integer.valueOf(element.getAttribute("value")));
}
}
}
students.add(student);
}
|
执行程序并点击“DOM解析”:
SAX解析xml
SAX是Simple API for XML的缩写,SAX是基于事件驱动的,在用SAX解析xml文档时候,在读取到文档开始和结束标签时候就会回调一个事件,在读取到其它节点与内容时也会回调一个事件.事件源是org.xml.sax包中的XMLReader,它通过parser()方法来解析XML文档,并产生事件.事件处理器是DefaultHandler,DefaultHandler的一些主要事件回调方法如下:
返回值 | 方法 | 描述 |
void | startDocument() Receive notification of the beginning of the document. | 文档解析开始时触发 |
void | startElement(String uri, String localName, String qName, Attributes attributes) Receive notification of the start of an element. | 某节点开始解析时触发 |
void | characters(char[] ch, int start, int length) Receive notification of character data inside an element. | 解析到文本节点时触发 |
void | endDocument() Receive notification of the end of the document. | 文档解析完成时触发 |
void | endElement(String uri, String localName, String qName) Receive notification of the end of an element. | 某节点解析完成 |
与DOM比较而言,SAX是一种轻量型的方法.当需要一个速度快的解析器并且希望最大限度的减少应用程序的内存占用时,通常可以使用SAX解析.
要解析的xml文件:student.xml置于raw/xml目录中
<?xml version="1.0" encoding="utf-8"?>
<students>
<student id="8">
<name>张三</name>
<age value="20"></age>
</student>
<student id="9">
<name>李四</name>
<age value="21"></age>
</student>
<student id="10">
<name>王五</name>
<age value="22"></age>
</student>
</students>
|
第一步:获取SAX工厂SAXParseFactory:
SAXParserFactory spf = SAXParserFactory.newInstance();
|
SAXParserFactory是SAXParser的工厂类。用来实例化SAXParser解析器
第二步:实例化SAXParser解析器
SAXParser sf = spf.newSAXParser();
|
由于SAX解析方式的特点是基于事件驱动型的。所以要使用此种方式解析需要获得事件源和事件处理器。
第四步:获取事件源:
XMLReader xmlReader = sf.getXMLReader();
|
第五步:创建事件处理器。
一个事件处理器需要继承DefaultHandler。并重写上面提到的五个方法
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.bawei.xml.Student;
import android.util.Log;
publicclass StudentHandler extends DefaultHandler {
private List<Student> mStudents;
private String mTagName = "";
private Student mStudent;
public StudentHandler(List<Student> students){
this.mStudents = students;
}
//开始解析文档
@Override
publicvoid startDocument() throws SAXException {
Log.d("TAG", "startDocument");
super.startDocument();
}
xml文档结尾
@Override
publicvoid endDocument() throws SAXException {
Log.d("TAG", "endDocument");
super.endDocument();
}
//解析开始标签
@Override
publicvoid startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
Log.d("TAG", "startElement localName: " + localName);
mTagName = localName;
if("student".equals(mTagName)){
mStudent = new Student();
mStudent.setId(Integer.valueOf(attributes.getValue("id")));
}elseif("age".equals(mTagName)){
mStudent.setAge(Integer.valueOf(attributes.getValue(0)));
}
super.startElement(uri, localName, qName, attributes);
}
//解析标签结束
@Override
publicvoid endElement(String uri, String localName, String qName)
throws SAXException {
Log.d("TAG", "endElement");
mTagName = localName;
if("student".equals(mTagName)){
mStudents.add(mStudent);
mStudent = null;
}
mTagName = "";
super.endElement(uri, localName, qName);
}
//解析文本节点
@Override
publicvoid characters(char[] ch, int start, int length)
throws SAXException {
String name = new String(ch, start, length);
Log.d("TAG", "characters name: " + name);
if(!name.trim().equals("") && "name".equals(mTagName)){
mStudent.setName(name);
}
super.characters(ch, start, length);
}
}
|
第六步:将事件处理器设置到事件源:
xmlReader.setContentHandler(studentHandler);
|
第七步:解析事件触发,读取raw下的文件:
xmlReader.parse(new InputSource(getResources().openRawResource(R.raw.students)));
|
注意:着重注意的是如何读取raw中的资源文件
执行程序并点击“SAX解析”:
PULL解析xml
XmlPullParser解析器的运行方式与SAX解析器相似.它提供了类似的事件(开始元素和结束元素),但需要使用parser.next()方法来提取它们.事件将作为数值代码被发送,因此可以根据不同的事件代码值来进行不同的处理.通过parser.getEventType()方法来取得事件的代码值
XmlPullParser解析xml文件时的五个事件的代码值:
类型 | 值 | 描述 |
int | START_DOCUMENT | 开始进行解析时触发的事件代码 |
Int | END_DOCUMENT | 解析结束时的事件代码 |
Int | TEXT | 解析文本节点时的事件代码 |
Int | START_TAG | 解析到某节点开始位置时触发的事件代码 |
int | END_TAG | 解析完毕某节点时触发的事件 |
要解析的xml文件:student.xml置于src/根目录中
<?xml version="1.0" encoding="utf-8"?>
<students>
<student id="8">
<name>张三</name>
<age value="20"></age>
</student>
<student id="9">
<name>李四</name>
<age value="21"></age>
</student>
<student id="10">
<name>王五</name>
<age value="22"></age>
</student>
</students>
|
第一步:获得XmlPullParser解析器
XmlPullParser parser = Xml.newPullParser(); |
第二步:读取资源文件:
parser.setInput(PullActivity.this.getClassLoader() //类加载器
.getResourceAsStream("students.xml"), "utf-8");
|
注意:着重注意如何读取项目根目录下的文件
第三步:通过获取事件类型的代码值进行相应的解析操作:
//获取事件类型码
int event = parser.getEventType();
Student student = null;
while(event!=XmlPullParser.END_DOCUMENT){
switch(event){
case XmlPullParser.START_DOCUMENT:
break;
case XmlPullParser.START_TAG:
//获取标签名字
if("student".equals(parser.getName())){
student = new Student();
student.setId(Integer.valueOf(parser.getAttributeValue(0)));
}
if(student!=null){
if("name".equals(parser.getName())){
//获取标签下一个文本节点的值
student.setName(parser.nextText());
}elseif ("age".equals(parser.getName())){
student.setAge(Integer.valueOf(parser.getAttributeValue(0)));
}
}
break;
case XmlPullParser.END_TAG:
if("student".equals(parser.getName())){
students.add(student);
student = null;
}
break;
case XmlPullParser.TEXT:
break;
}
//触发下一次事件
event = parser.next();
}
|
执行程序并点击“PULL解析”: