读取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 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());
- }
- }
- }