前言
Andorid XML有SAX, DOM, Pull三种解析方式。本文以下面的xml为例。
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student>
<name>张三</name>
<studentId>12</studentId>
<score>67</score>
</student>
<student>
<name>李四</name>
<studentId>13</studentId>
<score>79</score>
</student>
<student>
<name>王五</name>
<studentId>14</studentId>
<score>92</score>
</student>
</students>
1.SAX解析
SAX(Simple API for XML)解析器是一种基于事件的解析器,从文件的开始顺序解析到文档的结束,不可暂停或倒退。
- 优点:解析速度快,占用内存少。
- 缺点:不会记录标签的关系,而要让你的应用程序自己处理,增加程序负担。
新建XMLContentHandler类继承DefaultHandler,重写startDocument,startElement,characters,endElement方法。只需要传入InputStream即可,代码如下:
package com.xml.test;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
public class XMLContentHandlerStudent extends DefaultHandler {
private List<Student> students = null;
private Student currentStudent;
private String tagName = null;//当前解析的元素标签
public static List<Student> readXmlBySAX(InputStream inputStream) {
try {
/**【创建解析器】**/
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
XMLContentHandlerStudent handler = new XMLContentHandlerStudent();
saxParser.parse(inputStream, handler);
inputStream.close();
return handler.getStudents();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public List<Student> getStudents() {
return students;
}
/**文档开始时,调用此方法**/
@Override
public void startDocument() throws SAXException {
students = new ArrayList<>();
}
/**
* 标签开始时,调用此方法
* uri 命名空间|localName是不带命名空间前缀的标签名|
* qName 带命名空间前缀的标签名|
* attributes 可以得到所有的属性名和对应的值
**/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (localName.equals("student")) {
currentStudent = new Student();
// currentStudent.setId(Integer.parseInt(attributes.getValue("id")));
}
this.tagName = localName;
}
/**
* 接收标签中字符数据时,调用此方法
* ch 存放标签中的内容,
* start 起始位置,
* length 内容长度
**/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (tagName != null) {
String data = new String(ch, start, length);
if (tagName.equals("name")) {
this.currentStudent.setName(data);
} else if (tagName.equals("studentId")) {
this.currentStudent.setStudentId(Short.parseShort(data));
} else if (tagName.equals("score")) {
this.currentStudent.setScore(Short.parseShort(data));
}
}
}
/**
* 标签结束时,调用此方法
* localName 表示元素本地名称(不带前缀)
* qName 表示元素的限定名(带前缀)
**/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (localName.equals("student")) {
students.add(currentStudent);
currentStudent = null;
}
this.tagName = null;
}
}
2.DOM解析
DOM(Document Object Model)是将其转换为一个对象模型的集合,用树这种数据结构对信息进行储存,通过DOM接口,应用程序可以在任何时候访问xml文档中的任何一部分数据。
- 优点:易用性强,使用DOM时,将把所有的XML文档信息都存于内存中,并且遍历简单,支持XPath,增强了易用性。
- 缺点:效率低,解析速度慢,内存占用量过高,对于大文件来说几乎不可能使用。
public static List<Student> readXmlByDOM(InputStream inputStream){
List<Student> students = new ArrayList<>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document dom = builder.parse(inputStream);
Element rootElement = dom.getDocumentElement();
NodeList items = rootElement.getElementsByTagName("student");
for (int i = 0; i < items.getLength(); i++) {
Element elementItem = (Element) items.item(i);
NodeList childsNodes = elementItem.getChildNodes();
Student student = new Student();
for (int j = 0; j < childsNodes.getLength(); j++) {
Node node = (Node) childsNodes.item(j);
// 判断是否为元素类型
if(node.getNodeType() == Node.ELEMENT_NODE){
Element childNode = (Element) node;
String nodeName = childNode.getNodeName();
// 判断对应元素
if ("name".equals(childNode.getNodeName())) {
student.setName(childNode.getFirstChild().getNodeValue());
}else if("studentId".equals(childNode.getNodeName())){
student.setStudentId(Integer.parseInt(childNode.getFirstChild().getNodeValue()));
} else if ("score".equals(childNode.getNodeName())) {
student.setScore(Integer.parseInt(childNode.getFirstChild().getNodeValue()));
}
}
}
students.add(student);
}
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return students;
}
3.Pull解析
Pull解析与SAX解析原理上类似,但提供了开始,结束元素,并且提供了NEXT方法主动提取。在移动端而言,Pull解析最优。
public static List<Student> readXmlByPull(InputStream inputStream) {
XmlPullParser parser = Xml.newPullParser();
try {
parser.setInput(inputStream, "UTF-8");
int eventType = parser.getEventType();
Student currenStudent = null;
List<Student> students = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT: // 文档开始事件
students = new ArrayList<>();
break;
case XmlPullParser.START_TAG: // 元素(即标签)开始事件
String name = parser.getName();
if (name.equals("student")) {
currenStudent = new Student();
} else if (currenStudent != null) {
// 判断标签名(元素名)
if (name.equals("name")) {
currenStudent.setName(parser.nextText());
} else if (name.equals("studentId")) {
currenStudent.setStudentId(Integer.valueOf(parser.nextText()));
} else if (name.equals("score")) {
currenStudent.setScore(Integer.valueOf(parser.nextText()));
}
}
break;
case XmlPullParser.END_TAG:// 元素结束事件
if (parser.getName().equalsIgnoreCase("student") && currenStudent != null) {
students.add(currenStudent);
currenStudent = null;
}
break;
}
eventType = parser.next();
}
inputStream.close();
return students;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
网友评论