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