Android数据解析之XML数据解析
Android数据解析之XML数据解析
在Android中有两种XML,JSON数据形式,XML数据解析有三种,DOM,SAX,PULL;JSON数据解析有JSON,GSON,FastJson.此篇文章解析XML解析。下一篇讲解JSON解析。
概述
定义:
XML(Extensible Markup Language的缩写,意为可扩展的标记语言),它是一种元标记语言,即定义了用于定义其他特定领域有关语义的、结构化的标记语言,这些标记语言将文档分成许多部件并对这些部件加以标识。
XML 文档定义方式有:文档类型定义(DTD)和XML Schema。
DTD定义了文档的整体结构以及文档的语法,应用广泛并有丰富工具支持。
XML Schema用于定义管理信息等更强大、更丰富的特征。XML能够更精确地声明内容,方便跨越多种平台的更有意义的搜索结果。它提供了一种描述结构数据的格式,简化了网络中数据交换和表示,使得代码、数据和表示分离,并作为数据交换的标准格式,因此它常被称为智能数据文档。
由于XML具有很强的扩展性,致使它需要很强的基础规则来支持扩展,所以在编写XML文件时,我们应该严格遵守XML的语法规则,一般XML语法有如下规则:
(1)起始和结束的标签相匹配;
(2)嵌套标签不能相互嵌套;
(3)区分大小写。
Android中解析XML数据的三种方式 :
DOM解析:文档对象模型(Document Object Model)将xml文件全部载入,组装成一颗dom树,然后通过节点以及节点之间的关系来解析xml文件。
SAX解析(Simple API for XML):事件驱动,解析速度快,占用内存少。
PULL解析:事件驱动, 在解析过程中, 我们需要自己获取产生的事件然后做相应的操作. Android系统内部在解析各种XML时是用PULL解析器。
XML数据解析方法分析
测试使用的XML数据:
<?xml version="1.0" encoding="utf-8"?>
<books>
<book>
<id>1001</id>
<name>Thinking In Java</name>
<price>80.00</price>
</book>
<book>
<id>1002</id>
<name>Core Java</name>
<price>90.00</price>
</book>
<book>
<id>1003</id>
<name>Hello, Andriod</name>
<price>100.00</price>
</book>
</books>
DOM解析
定义
DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。Android完全支持DOM 解析。利用DOM中的对象,可以对XML文档进行读取、搜索、修改、添加和删除等操作。
工作原理
DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档——这就是DOM的工作原理。DOM实现时首先为XML文档的解析定义一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,这样代码就可以使用DOM接口来操作整个树结构。由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。 当然,如果XML文件的内容比较小,采用DOM是可行的。
常用方法
接口或类名称 | 接口或类说明 |
---|---|
Document | 该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。 |
Element | 该接口继承Node接口,提供了获取、修改XML元素名字和属性的方法 |
Node | 该接口提供处理并获取节点和子节点值的方法 |
NodeList | 提供获得子节点个数和当前节点的方法。这样就可以迭代地访问各个节点 |
编程步骤
DOM解析XML的编程步骤:
1、创建文档对象工厂实例;
2、调用DocumentBuilderFactory中的newDocumentBuilder()方法创建文档对象构造器;
3、将文件流解析成XML文档对象;
4、使用mDocument文档对象得到文档根节点;
5、根据名称获取根节点中的子节点列表;
6 、获取子节点列表中需要读取的节点信息。
源码
Activity中调用
/*
DOM解析
*/
public void dom(View view) throws IOException {
InputStream is = getAssets().open("books.xml");
parseXMLWithDOM(is);
}
解析操作:
/*
DOM解析的操作
*/
private void parseXMLWithDOM(InputStream xmlData) {
String id = "";
String name = "";
String price = "";
//创建解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
//创建解析器
DocumentBuilder builder = factory.newDocumentBuilder();
//获得Document对象
Document document = builder.parse(xmlData);//流数据
// Document document = builder.parse(new InputSource(new StringReader(xmlData)));//字符串数据
NodeList bookList = document.getElementsByTagName("book");
for (int i = 0; i < bookList.getLength(); i++) {
//获得子节点的List
Node node_bookList = bookList.item(i);
//获得子节点List里面的节点
NodeList childNodes = node_bookList.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
Node childNode = childNodes.item(j);
//判断是name还是nickName
if ("id".equals(childNode.getNodeName())) {
id = childNode.getTextContent();
} else if ("name".equals(childNode.getNodeName())) {
name = childNode.getTextContent();
} else if ("price".equals(childNode.getNodeName())) {
price = childNode.getTextContent();
}
}
Log.e("TAG", "DOM解析的子节点数据:" + "\n" +
"id :" + id + "\n" +
"name : " + name + "\n" +
"price : " + price);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
测试结果
SAX解析
定义
SAX(Simple For XML)是一种基于事件的解析器,它的核心是事件处理模式,它主要是围绕事件源和事件处理器来工作的。当事件源产生事件后,会调用事件处理器中相应的方法来处理一个事件,那在事件源调用对应的方法时也会向对应的事件传递一些状态信息,以便我们根据其状态信息来决定自己的行为。
工作原理
SAX解析工作的主要原理:在读取XML文档内容时,事件源顺序地对文档进行扫描,当扫描到文档的开始与结束(Document)标签、节点元素的开始与结束(Element)标签时,直接调用对应的方法,并将状态信息以参数的形式传递到方法中,然后我们可以依据状态信息来执行相关的自定义操作。
常用方法
首先介绍一个类:DefaultHandler,该类是XML解析接口(EntityResolver, DTDHandler, ContentHandler, ErrorHandler)的缺省实现,在通常情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现这些接口更容易。接着重写startDocument(),startElement(),characters(),endElement和endDocument()五个方法,这些方法会在事件源(在org.xml.sax包中的XMLReader,通过parser()产生事件)读取到不同的XML标签所产生事件时调用。那我们开发时只要在这些方法中实现我们的自定义操作即可
方法名称 | 方法说明 |
---|---|
startDocument() | 用于处理文档解析开始时间 |
startElement(String uri, String localName, String qName, Attributes attributes) | 处理元素开始时间,从参数中可以获取元素所在空间的URL,元素名称,属性列表等信息 |
characters(char[] ch, int start, int length | 处理元素的字符内容,从参数中可以获得内容 |
endElement(String uri, String localName, String qName) | 处理元素结束时间,从参数中可以获取元素所在空间的URL,元素名称等信息。 |
endDocument() | 用于处理文档解析的结束事件 |
编程步骤
SAX解析XML的编程步骤:
1、获取创建一个SAX解析工厂实例;
2、调用工厂实例中的newSAXParser()方法创建SAXParser解析对象;
3、实例化CustomHandler(DefaultHandler的子类);
4、连接事件源对象XMLReader到事件处理类DefaultHandler中;
5、通过DefaultHandler返回我们需要的数据集合。
源码
/*
sax解析
*/
public void sax(View view) throws IOException {
InputStream is = getAssets().open("books.xml");
parseXMLWithSAX(is);
}
/*
SAX解析的操作
*/
private void parseXMLWithSAX(InputStream xmlData) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
ContentHandler handler = new ContentHandler();
// 将ContentHandler的实例设置到XMLReader中
xmlReader.setContentHandler(handler);
// 开始执行解析
xmlReader.parse(new InputSource(xmlData));//流数据
// xmlReader.parse(new InputSource(new StringReader(xmlData)));//字符串数据
} catch (Exception e) {
e.printStackTrace();
}
}
public class ContentHandler extends DefaultHandler {
private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder price;
@Override
public void startDocument() throws SAXException {
id = new StringBuilder();
name = new StringBuilder();
price = new StringBuilder();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// 记录当前结点名
nodeName = localName;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// 根据当前的结点名判断将内容添加到哪一个StringBuilder对象中
if ("id".equals(nodeName)) {
id.append(ch, start, length);
} else if ("name".equals(nodeName)) {
name.append(ch, start, length);
} else if ("price".equals(nodeName)) {
price.append(ch, start, length);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("book".equals(localName)) {
Log.e("TAG", "SAX解析的子节点数据:" + "\n" +
"id :" + id.toString().trim() + "\n" +
"name : " + name.toString().trim() + "\n" +
"price : " + price.toString().trim());
// 最后要将StringBuilder清空掉
id.setLength(0);
name.setLength(0);
price.setLength(0);
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
}
测试结果
PULL解析
定义
PULL的解析方式与SAX解析类似,都是基于事件的模式。不同的是,在PULL解析过程中返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。
工作原理
PULL 的工作原理:XML pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。
常用方法
常用的接口类
接口和类名称 | 接口和类说明 |
---|---|
XmlPullParser | XML Pull解析接口,该接口定义了解析功能 |
XmlSerializer | 它是一个接口,定义了XML信息集的序列 |
XmlPullParserFactory | XML PULL解析工厂类,用于创建XML Pull解析器 |
XmlPullParserException | 抛出单一的XML pull解析器相关的错误 |
常用方法
方法名 | 方法说明 |
---|---|
getEventType() | 该方法用于获取当前解析到的事件类型 |
nextText() | 提取当前节点元素的字符数据 |
next() | 获取下一个节点元素的类型 |
getName() | 获取当前节点元素的名称 |
getAttributeCount() | 获取当前节点属性的数量 |
XmlPullParser的接口类型
接口类型 | 接口类型说明 |
---|---|
XmlPullParser.START_DOCUMENT | 文档开始解析类型 |
XmlPullParser.END_DOCUMENT | 文档结束解析类型 |
XmlPullParser.START_TAG | 节点开始解析类型 |
XmlPullParser.END_TAG | 节点结束解析类型 |
XmlPullParser.TEXT | 文本解析类型 |
编程步骤
PULL解析XML的编程步骤:
1、获取PULL解析工厂实例对象;
2、使用XmlPullParserFactory的newPullParser()方法实例化PULL解析实例对象;
3、设置需解析的XML文件流和字符编码;
4、获取事件解析类型;
5、循环遍历解析,当文档解析结束时结束循环;
源码
public void pull(View view) throws IOException {
InputStream is = getAssets().open("books.xml");
parseXMLWithPull(is);
/*
读取流数据
*/
InputStreamReader inputStreamReader = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(inputStreamReader);
String buf = null;
String resultxml = "";
StringBuffer sb = new StringBuffer();
while ((buf = reader.readLine()) != null) {
sb.append(buf);
resultxml = sb.toString();
Log.i("TAG", " resultxml--->" + sb.toString());
}
is.close();
}
/*
Pull解析的操作
*/
private void parseXMLWithPull(InputStream xmlData) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(xmlData, "UTF-8");//流数据
// xmlPullParser.setInput(new StringReader(xmlData));//字符串数据
int eventType = xmlPullParser.getEventType();
String id = "";
String name = "";
String price = "";
while (eventType != XmlPullParser.END_DOCUMENT) {
String nodeName = xmlPullParser.getName();
switch (eventType) {
// 开始解析某个结点
case XmlPullParser.START_TAG: {
if ("id".equals(nodeName)) {
id = xmlPullParser.nextText();
} else if ("name".equals(nodeName)) {
name = xmlPullParser.nextText();
} else if ("price".equals(nodeName)) {
price = xmlPullParser.nextText();
}
break;
}
// 完成解析某个结点
case XmlPullParser.END_TAG: {
if ("book".equals(nodeName)) {
Log.e("TAG", "Pull解析的子节点数据:" + "\n" +
"id :" + id + "\n" +
"name : " + name + "\n" +
"price : " + price);
}
break;
}
default:
break;
}
eventType = xmlPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
}
测试结果
三种解析XML方法的比较
SAX解析器的特点:SAX解析器解析速度快、高效,占用内存少。但它的缺点是编码实现比其它解析方式更复杂,对于只需解析较少数量的XML文件时,使用SAX解析显得实现代码比较臃肿。
DOM解析器的特点:由于DOM在内存中是以树形结构存放的,那虽然检索和更新效率比较高,但对于使用DOM来解析较大数据的XML文件,将会消耗很大内存资源,这对于内存资源比较有限的手机设备来讲,是不太适合的。
PULL解析器的特点:PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用。Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。
测试Demo地址
github:https://github.com/TDCQZD/AndroidJson
上一篇: 腌肉的时候放小苏打能有什么用