上一篇文章用一个简单例子讲了下SAX方式解析XML文件的用法及特点,可点击查看:
Android XML文件解析之SAX解析 简单示例讲解
本篇文章,我们接着用个简单例子展示一下PULL方式解析XML。
先介绍下PULL方式解析XML的特点,它和SAX方式的相同之处是都是事件驱动的流式解析方式,一边读取XML内容一边解析,不可暂停或者倒退,直到结束。效率高,占用内存小。
而和SAX解析的不同点在于,PULL解析过程中并不会触发方法回调,而是会产生类似“开始新节点”,“结束一个节点”这样的事件,用数字表示。我们需要对这些事件做判断处理。
另外,Android系统本身使用到的各种xml文件,其内部也是采用Pull解析器进行解析的。
接下来是实例,前面两步准备工作和上一篇SAX解析的一样:
一、先准备一个简单的xml文件。
路径:res/raw/person_data.xml:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<person id="5">
<name>Jack</name>
<age>25</age>
</person>
<person id="20">
<name>Rose</name>
<age>80</age>
</person>
</data>
二、新建一个Person类。
我们的目标是把上面的xml数据(两个person)转换成一个Person列表。
Person类如下,和xml里的属性一一对应:
public class Person {
private int id;
private String name;
private int age;
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
下面先看看如何用PULL方式解析上面的xml:
三、得到PULL解析器
PULL方式解析xml,就不用自定义解析器了,可以使用现有的类得到解析器。
这里介绍两种PULL解析器,XmlPullParser和XmlResourceParser,其中后者是前者的子类。
1、XmlPullParser解析器:
public static XmlPullParser getXmlPullParser(Context context) {
XmlPullParser pullParser = null;
try {
// 创建Pull解析器
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
pullParser = factory.newPullParser();
// 设置xml数据源
InputStream inputStream = context.getResources().openRawResource(R.raw.person_data);
pullParser.setInput(new InputStreamReader(inputStream));
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return pullParser;
}
2、XmlResourceParser解析器:
这种方式更加简单,
XmlResourceParser pullParser = context.getResources().getXml(R.xml.person_data);
但是注意这种方式,xml文件需要放到res/xml文件夹下才行。
然后下面是解析的实现。
四、PULL方式解析实现
把第三步得到的 pullParser 传入下面的方法中运行即可得到解析结果。
public static void pullParseXml(XmlPullParser pullParser) {
List<Person> personList = null; // 存储最终得到的结果
Person person = null; // 当前正在解析的Person
try {
int eventType = pullParser.getEventType();
// 开始解析。如果解析遇到的事件是文件解析结束的话就退出循环
while (eventType != XmlPullParser.END_DOCUMENT) {
String currentNodeName = pullParser.getName();
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
// 开始解析,可以在这里做一些初始化
personList = new ArrayList<>();
Log.d(TAG, "START_DOCUMENT: node == " + currentNodeName);
break;
case XmlPullParser.START_TAG:
// 开始解析某个节点
if (currentNodeName.equals("person")) {
// 开始节点是“person”,则开始一个新Person的解析
person = new Person();
// 获取id属性
String idStr = pullParser.getAttributeValue(null, "id");
person.setId(Integer.parseInt(idStr));
} else if (currentNodeName.equals("name")) {
// 获取name
person.setName(pullParser.nextText());
} else if (currentNodeName.equals("age")) {
// 获取age
person.setAge(Integer.parseInt(pullParser.nextText()));
}
Log.d(TAG, "START_TAG: node == " + currentNodeName);
break;
case XmlPullParser.END_TAG:
// 结束某个节点的解析
if (currentNodeName.equals("person")) {
// 如果person节点结束的话,就把已解析的person对象加入列表
personList.add(person);
}
Log.d(TAG, "END_TAG: node == " + currentNodeName);
break;
case XmlPullParser.END_DOCUMENT:
// 结束文件解析,这里不会走到,因为我们把它作为while循环的终止条件
break;
default:
break;
}
// 继续解析下一个事件
eventType = pullParser.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 打印最终结果
Log.d(TAG, "personList == " + personList);
}
运行结果:
personList == [Person{id=5, name='Jack', age=25}, Person{id=20, name='Rose', age=80}]
为了更直观的查看解析过程,我在上面的方法每一步都加上了log,打印log结果如下,可对照查看:
D/TAG: START_DOCUMENT: node == null
D/TAG: START_TAG: node == data
START_TAG: node == person
START_TAG: node == name
START_TAG: node == age
D/TAG: END_TAG: node == person
START_TAG: node == person
START_TAG: node == name
D/TAG: START_TAG: node == age
END_TAG: node == person
END_TAG: node == data
再贴个上一篇的链接,方便对照理解:
Android XML文件解析之SAX解析 简单示例讲解