读取XML主要有2种方法:DOM与SAX(Simple API for XML),在这里对这2种方法分别加以说明。
DOM(文档对象模型),为XML文档的解析定义了一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,然后代码就可以使用DOM接口来 操组整个树结构,其他点如下:
- 优点:整个文档树都在内存当中,便于操作;支持删除、修改、重新排列等多功能。
- 缺点:将整个文档调入内存(经常包含大量无用的节点),浪费时间和空间。
- 使用场合:一旦解析了文档还需要多次访问这些数据,而且资源比较充足(如内存、CPU等)。
为了解决DOM解析XML引起的这些问题,出现了SAX。SAX解析XML文档为事件驱动。当解析器发现元素开始、元素结束,文本、文档的开始或者结束时,发送 事件,在程序中编写响应这些事件的代码,其特点如下:
- 优点:不用事先调入整个文档,占用资源少。尤其在嵌入式环境中,极力推荐采用SAX进行解析XML文档。
- 缺点:不像DOM一样将文档长期驻留在内存,数据不是持久的,事件过后,如没有保存数据,那么数据就会丢失。
- 使用场合:机器性能有限,尤其是在嵌入式环境,如Android,极力推荐采用SAX进行解析XML文档。
大多数时间,使用 SAX 是比较安全的,并且 Android 提供了一种传统的 SAX 使用方法,以及一个便捷的 SAX 包装器。如果XML文档比较小,那么 DOM 可能是一种比较简单的方法。如果XML文档比较大,但只需要文档的一部分,则 XML Pull 解析器可能是更为有效的方法。最后对于编写 XML,Pull 解析器包也提供了一种便捷的方法。因此,无论我们的 XML 需求如何,Android 都能在一定程度上满足我们的需求。
下面我们详细介绍采用DOM的方法,读取XML文档的思路,这基本上与XML的结构是完全一样的。
首先加载XML文档(Document),
然后获 取文档的根结点(Element),
然后获取根结点中所有子节点的列表(NodeList),
然后使用再获取子节点列表中的需要读取的结点。
采用DOM读取XML文件,需要加载整个XML文件,在XML文件比较大的情况下,会导致Android设备内存紧张,为了避免这个问题,也可以采 用SAX的方法读取XML文件,不过SAX对结点的排序、增加结点等方面的操作相比DOM就有些复杂了。根据XML文件大小、数据处理的需求,选择合适的 读取的方法。
XML代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<student id="2">
<name>张三</name>
<age>23</age>
</student>
<student id="5">
<name>李四</name>
<age>25</age>
</student>
</person>
DOM解析:
java类代码:
package com.utils.parsexml;
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;
/**
* 使用DOM解析XML
*
* @author 伟
*
*/
public class DomXMLTools {
public static List<Student> parseXML(InputStream is) throws Exception {
List<Student> stus = new ArrayList<Student>();
Student stu = null;
// 创建一个document解析工厂
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
Element element = doc.getDocumentElement();
NodeList stuNodes = element.getElementsByTagName("student");
for (int i = 0; i < stuNodes.getLength(); i++) {
Element stuNode = (Element) stuNodes.item(i);
stu = new Student();
int id = Integer.parseInt(stuNode.getAttribute("id"));
stu.setId(id);
NodeList stuChilds = stuNode.getChildNodes();
for (int j = 0; j < stuChilds.getLength(); j++) {
Node childs = stuChilds.item(j);
// 得到节点可能为回车或空格,所以必须判断
if (childs.getNodeType() == Node.ELEMENT_NODE) {
if (childs.getNodeName().equals("name")) {
String name = childs.getFirstChild().getNodeValue();
stu.setName(name);
} else if (childs.getNodeName().equals("age")) {
String ageStr = childs.getFirstChild().getNodeValue();
int age = Integer.parseInt(ageStr);
stu.setAge(age);
}
}
}
stus.add(stu);
}
return stus;
}
}
Pull解析:
java类代码
package com.utils.parsexml;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
/**
* 使用pull解析XML
*
* @author 伟
*
*/
public class PullXMLTools {
public static List<Student> parseXML(InputStream is, String encode)
throws Exception {
List<Student> list = null;
Student stu = null;
// 新建一个XMLpull解析工厂
XmlPullParserFactory xf = XmlPullParserFactory.newInstance();
// 获得XML解析类的引用
XmlPullParser xp = xf.newPullParser();
xp.setInput(is, encode);
// 获得事件的类型
int type = xp.getEventType();
while (type != XmlPullParser.END_DOCUMENT) {
switch (type) {
case XmlPullParser.START_DOCUMENT:
// XML文档开始
list = new ArrayList<Student>();
break;
case XmlPullParser.START_TAG:
// 解析一个开始标签,获取标签文本
String tagName = xp.getName();
if (tagName.equals("student")) {
stu = new Student();
// 获得属性值
int id = Integer.parseInt(xp.getAttributeValue(0));
stu.setId(id);
} else if (tagName.equals("name")) {
// 获取节点内容
String name = xp.nextText();
stu.setName(name);
} else if (tagName.equals("age")) {
int age = Integer.parseInt(xp.nextText());
stu.setAge(age);
}
break;
case XmlPullParser.END_TAG:
// 解析一个结束标签,并清空当前学生对象
if (xp.getName().equals("student")) {
list.add(stu);
stu = null;
}
break;
}
// 重新获取事件类型
type = xp.next();
}
return list;
}
}
SAX解析:
handler类:
package com.utils.parsexml;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* 解析XML处理器
*
* @author 伟
*
*/
public class SaxHandler extends DefaultHandler {
private List<Student> stus;
private Student stu;
private String currentTag;
private String currentValue;
public List<Student> getStus() {
return stus;
}
@Override
public void startDocument() throws SAXException {
// 开始解析XML
stus = new ArrayList<Student>();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// 开始读取标签,qName为标签文本
currentTag = qName;
if (currentTag.equals("student")) {
stu = new Student();
if (attributes != null) {
String idStr = attributes.getValue(0);
int id = Integer.parseInt(idStr);
stu.setId(id);
}
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// 根据currentTag获取每个标签的内容
if (currentTag != null) {
currentValue = new String(ch, start, length);
// 确保value不是回车或者空字符
if (currentValue != null && !currentValue.trim().equals("")
&& !currentValue.trim().equals("\n")) {
if (currentTag.equals("name")) {
stu.setName(currentValue);
} else if (currentTag.equals("age")) {
stu.setAge(Integer.parseInt(currentValue));
}
}
}
// 把当前节点对应的值清空
currentTag = null;
currentValue = null;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// 遇到结束标签时调用
currentTag = qName;
if (currentTag.equals("student")) {
stus.add(stu);
stu = null;
}
}
}
java解析类:
package com.utils.parsexml;
import java.io.InputStream;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class SaxXMLTools {
public static List<Student> parseXML(InputStream is) throws Exception {
List<Student> stus = null;
// 创建一个XML解析处理器
SaxHandler sh = new SaxHandler();
// 创建一个SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
// 创建SAX解析器
SAXParser sp = spf.newSAXParser();
// 解析xml,将每个事件发给处理器
sp.parse(is, sh);
is.close();
return sh.getStus();
}
}
实体类:
package com.utils.parsexml;
public class Student {
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;
}
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Studnet [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
测试类:
package com.utils.parsexml;
import java.io.InputStream;
import java.util.List;
public class Test {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
InputStream is = Test.class.getClassLoader().getResourceAsStream(
"person.xml");
// List<Student> stus = PullXMLTools.parseXML(is, "utf-8");
// List<Student> stus = DomXMLTools.parseXML(is);
List<Student> stus = SaxXMLTools.parseXML(is);
for (Student student : stus) {
System.out.println(student.toString());
}
}
}