解析XML有三种方式:Dom、SAX、Pull
其中pull解析器运行方式与SAX类似。
我们首先认识pull解析器:http://developer.android.com/intl/zh-cn/reference/org/xmlpull/v1/XmlPullParser.html
Th following event types are seen by next()
- START_TAG
- An XML start tag was read.
- TEXT
- Text content was read; the text content can be retrieved using the getText() method. (when in validating mode next() will not report ignorable whitespace, use nextToken() instead)
- END_TAG
- An end tag was read
- END_DOCUMENT
- No more events are available
1.解析
获取解析器: Xml.newPullParser()
设置输入流: parser.setInput(InputStream, String)
获取当前事件类型: parser.getEventType(),
获取下一个事件类型: parser.next()
获取标签名: parser.getName()
获取属性值: parser.getAttributeValue(int)、getAttributeValue(null,"id")
获取下一个文本: parser.nextText()
2.生成
获取解析器:
设置输出流:
开始文档:
结束文档:
开启标签:
结束标签:
设置属性:
设置文本:
下面我们用一个实例来看看:
在src下面新建presons.xml
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<persons>
<person id="1">
<name>范冰冰</name>
<age>31</age>
</person>
<person id="2">
<name>林志玲</name>
<age>38</age>
</person>
<person id="3">
<name>杨幂</name>
<age>26</age>
</person>
</persons>
然后在包中创建Person.java、PersonService.java、PersonTest.java
public class PersonService { public List<Person> loadPersons(InputStream in) throws Exception {
XmlPullParser parser = Xml.newPullParser(); // 获取解析器
parser.setInput(in, "UTF-8"); // 设置输入流, 指定码表 ArrayList<Person> persons = new ArrayList<Person>();
Person p = null; // 最初type赋值为第一个事件, 只要不是文档结束就循环, 每次循环后解析下一个事件
for (int type = parser.getEventType(); type != XmlPullParser.END_DOCUMENT; type = parser.next()) {
if (type == XmlPullParser.START_TAG) { // 如果遇到了标签开始事件
if (parser.getName().equals("person")) { // 如果标签名为"person"
p = new Person(); // 创建对象
String id = parser.getAttributeValue(0); // 获取第一个属性的属性值
p.setId(Integer.parseInt(id)); // 转为int, 设置id
persons.add(p); // 装入集合
} else if (parser.getName().equals("name")) { // 如果标签名为"name"
String name = parser.nextText(); // 获取下一个文本
p.setName(name); // 设置name
} else if (parser.getName().equals("age")) { // 如果标签名为"age"
String age = parser.nextText(); // 获取下一个文本
p.setAge(Integer.parseInt(age)); // 设置age
}
}
} return persons;
} public void savePersons(List<Person> persons, OutputStream out) throws IOException {
XmlSerializer serializer = Xml.newSerializer(); // 获取序列化工具
serializer.setOutput(out, "UTF-8"); // 设置输出流, 指定码表 serializer.startDocument("UTF-8", true); // 开始文档
serializer.startTag(null, "persons"); // 开始标签 for (Person p : persons) {
serializer.startTag(null, "person");
serializer.attribute(null, "id", p.getId().toString()); // 设置属性 serializer.startTag(null, "name");
serializer.text(p.getName()); // 设置文本
serializer.endTag(null, "name"); serializer.startTag(null, "age");
serializer.text(p.getAge().toString());
serializer.endTag(null, "age"); serializer.endTag(null, "person");
} serializer.endTag(null, "persons"); // 结束标签
serializer.endDocument(); // 结束文档
} }
public class PersonTest extends AndroidTestCase { public void testLoad() throws Exception {
PersonService service = new PersonService();
InputStream in = PersonTest.class.getClassLoader().getResourceAsStream("persons.xml");
List<Person> persons = service.loadPersons(in);
for (Person p : persons)
System.out.println(p); Person p = new Person(4, "张红", 18);
persons.add(p);
service.savePersons(persons, new FileOutputStream("/mnt/sdcard/persons.xml"));
} }
public class Person {
private Integer id;
private String name;
private Integer age; public Person() {
super();
} public Person(Integer id, String name, Integer age) {
super();
this.id = id;
this.name = name;
this.age = age;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} @Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
} }
然后运行程序,可在日志中看到解析的数据。
(最好添加一个日志信息的过滤器,专门查看System.out输出的信息)
以上部分只讲解了PULL解析,下面我们用这三种解析方式解析同一个XML文件(在代码中注释讲解)。
需要我们解析的XML内容如下:
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<persons>
<person id="1">
<name>saber</name>
<age>20</age>
</person>
<person id="2">
<name>Archer</name>
<age>21</age>
</person>
<person id="3">
<name>Lancer</name>
<age>26</age>
</person>
</persons>
其存放在名为“assets”的文件夹下,取名为“test”。
整个程序代码文件如下:
接下来,实现一个实体类,该类的属性应与XML文件对应,名为“Person.java”,其实现如下:
package com.topcsa.entity; public class Person {
private Integer id;
private String name;
private Integer age; public Person() {
super();
} public Person(Integer id, String name, Integer age) {
super();
this.id = id;
this.name = name;
this.age = age;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} @Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
} }
名为“XmlUtils.java”的文件实现如下:
package com.topcsa.utils; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory; import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import com.topcsa.entity.Person; import android.content.Context;
import android.util.Xml; public class XmlUtils { public List<Person> XmlPullParse(Context con) {
InputStream inputStream = null;
ArrayList<Person> persons = new ArrayList<Person>();
Person p = null;
XmlPullParser parser = Xml.newPullParser(); // 获取解析器
// 得到文件流,并设置编码方式
try {
inputStream = con.getResources().getAssets().open("test.xml");
parser.setInput(inputStream, "UTF-8"); // 设置输入流, 指定码表
// 最初type赋值为第一个事件, 只要不是文档结束就循环, 每次循环后解析下一个事件
for (int type = parser.getEventType(); type != XmlPullParser.END_DOCUMENT; type = parser
.next()) {
if (type == XmlPullParser.START_TAG) { // 如果遇到了标签开始事件
if (parser.getName().equals("person")) { // 如果标签名为"person"
p = new Person(); // 创建对象
String id = parser.getAttributeValue(0); // 获取第一个属性的属性值
p.setId(Integer.parseInt(id)); // 转为int, 设置id
persons.add(p); // 装入集合
} else if (parser.getName().equals("name")) { // 如果标签名为"name"
String name = parser.nextText(); // 获取下一个文本
p.setName(name); // 设置name
} else if (parser.getName().equals("age")) { // 如果标签名为"age"
String age = parser.nextText(); // 获取下一个文本
p.setAge(Integer.parseInt(age)); // 设置age
} }
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} return persons; } public List<Person> XmlSaxParse(Context con) { List<Person> persons = null;
// 建立Sax解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// 取得SaxParser对象
SAXParser parser = factory.newSAXParser();
// 获取事件源
XMLReader xmlReader = parser.getXMLReader();
// 设置sax解析器
PersonSaxHandler handler = new PersonSaxHandler();
xmlReader.setContentHandler(handler);
// 解析xml文档
xmlReader.parse(new InputSource(con.getAssets().open("test.xml")));
persons = handler.getPersons();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} return persons; } public List<Person> XmlDomParse(Context con) {
List<Person> persons = new ArrayList<Person>();
DocumentBuilderFactory factory = null;
DocumentBuilder builder = null;
Document document = null;
InputStream inputStream = null;
// 建立DocumentBuilderFactory对象,用于取得DocumentBuilder
factory = DocumentBuilderFactory.newInstance();
try {
// 找到XML文档
inputStream = con.getResources().getAssets().open("test.xml");
// 通过DocumentBuilderFactory取得DocumentBuilder
builder = factory.newDocumentBuilder();
// 读取指定路径的XML文件
document = builder.parse(inputStream);
// 找到根Element
Element root = document.getDocumentElement();
NodeList nodes = root.getElementsByTagName("person");
// 遍历所有根节点下的子节点,persons下的所有person
Person person = null;
for (int i = 0; i < nodes.getLength(); i++) {
person = new Person();
// 获取person元素节点
Element personElement = (Element) (nodes.item(i));
// 获取person中id属性值
person.setId(Integer.parseInt(personElement.getAttribute("id")));
// 获取person下name标签
Element personName = (Element) personElement
.getElementsByTagName("name").item(0);
person.setName(personName.getFirstChild().getNodeValue());
// 获取person下age标签
Element personAge = (Element) personElement
.getElementsByTagName("age").item(0);
person.setAge(Integer.parseInt(personAge.getFirstChild()
.getNodeValue()));
persons.add(person);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return persons; } //Sax解析方式需要的类
class PersonSaxHandler extends DefaultHandler { private List<Person> list = null;
private String elementName = null;
private Person person = null; @Override
public void startDocument() throws SAXException {// 文档开始,实例化集合
// TODO Auto-generated method stub
this.list = new ArrayList<Person>();
} // 元素开始
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
localName = localName.toLowerCase().trim();
// 如果读取的是person标签开始,则实例化Person
if (localName.equals("person")) {
this.person = new Person();
// 导航到person开始节点后
this.person.setId(Integer.parseInt(attributes.getValue("id")));
}
// 保存元素名称
this.elementName = localName;
} @Override
public void characters(char[] ch, int start, int length)// 获取元素类容
throws SAXException {
if (this.elementName != null) {// 表示有元素
String data = new String(ch, start, length);// 取得文字信息
if (this.elementName.equals("name")) {
this.person.setName(data);
} else if (this.elementName.equals("age")) {
this.person.setAge(Integer.parseInt(data));
}
}
} // 元素结尾
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (localName.equals("person")) {// 判断元素标记是"person"
this.list.add(this.person);// 向集合中保存数据
this.person = null;// 清空对象
}
this.elementName = null;// 青空元素标记
} public List<Person> getPersons() {// 取得全部集合
return this.list; }
} }
MainActivity的布局文件activity_main.xml实现如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <Button
android:id="@+id/btn_dom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dom解析" /> <Button
android:id="@+id/btn_sax"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sax解析" /> <Button
android:id="@+id/btn_pull"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pull解析" /> <TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> </LinearLayout>
MainActivity的实现如下:
package com.topcsa.zhj_test; import java.util.ArrayList;
import java.util.List; import android.app.Activity;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView; import com.topcsa.entity.Person;
import com.topcsa.utils.XmlUtils; public class MainActivity extends Activity {
private XmlUtils xmlutils;
private List<Person> persons;
private StringBuffer sb;
private TextView tv; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnDom = (Button) findViewById(R.id.btn_dom);
Button btnSax = (Button) findViewById(R.id.btn_sax);
Button btnPull = (Button) findViewById(R.id.btn_pull);
xmlutils = new XmlUtils();
persons = new ArrayList<Person>();
sb = new StringBuffer(); btnDom.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) {
sb.append("Dom解析:");
persons = xmlutils.XmlDomParse(MainActivity.this);
for (int i = 0; i < persons.size(); i++) {
Person person = persons.get(i);
sb.append("姓名:" + person.getName() + ",id:"
+ person.getId() + ",年龄:" + person.getAge() + "; "); }
tv.setText(sb.toString());
}
});
btnSax.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) {
sb.append("Sax解析:");
persons = xmlutils.XmlSaxParse(MainActivity.this);
for (int i = 0; i < persons.size(); i++) {
Person person = persons.get(i);
sb.append("姓名:" + person.getName() + ",id:"
+ person.getId() + ",年龄:" + person.getAge() + "; "); }
tv.setText(sb.toString()); }
});
btnPull.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) {
sb.append("Pull解析:");
persons = xmlutils.XmlPullParse(MainActivity.this);
if (persons != null) {
System.out.println("不为空"+persons.size());
} else {
System.out.println("为空");
}
for (int i = 0; i < persons.size(); i++) {
Person person = persons.get(i);
sb.append("姓名:" + person.getName() + ",id:"
+ person.getId() + ",年龄:" + person.getAge() + "; "); }
tv.setText(sb.toString()); }
}); tv = (TextView) findViewById(R.id.tv); } }
最后程序运行如下: