Android中的xml解析

一、绪论

上周工作需要了解项目的一些大体内容,结果在xml解析这一块看的迷迷糊糊的,所以在这里把学习到xml解析的一些知识记录一下。

二、分析

android中的xml解析器主要有三种,DOM解析器、SAX解析器和pull解析器。

1、DOM解析器

DOM(Document Object Model) 是一种用于XML文档的对象模型,可用于直接访问XML文档的各个部分。它是一次性全部将内容加载在内存中,生成一个树状结构,它没有涉及回调和复杂的状态管理。 缺点是加载大文档时效率低下,所以一般在解析大文档时不建议使用DOM解析。

分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。Android完全支持DOM 解析。利用DOM中的对象,可以对XML文档进行读取、搜索、修改、添加和删除等操作。

DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档。

常用的DOM的接口和类:

Document:该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。

Node:该接口提供处理并获取节点和子节点值的方法。

Element:该接口继承Node接口,提供了获取、修改XML元素名字和属性的方法。

NodeList:提供获得节点个数和当前节点的方法。这样就可以迭代地访问各个节点。

DOMParser:该类是Apache的Xerces中的DOM解析器类,可直接解析XML文件。


2、SAX解析

SAX(Simple API for XML) 使用流式处理的方式,它并不记录所读内容的相关信息。它是一种以事件为驱动的XML API,解析速度快,占用内存少。使用回调函数来实现。 缺点是因为以事件为驱动的它不能回退。

它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。

SAX的工作原理:SAX会顺序扫描文档,在扫描到文档(document)开始与结束、元素(element)开始与结束、元素内容(characters)等时通知事件处理方法,事件处理方法进行相应处理,然后继续扫描,指导文档扫描结束。

常用的SAX接口和类:

Attrbutes:用于得到属性的个数、名字和值。

ContentHandler:定义与文档本身关联的事件(例如,开始和结束标记)。大多数应用程序都注册这些事件。

DTDHandler:定义与DTD关联的事件。它没有定义足够的事件来完整地报告DTD。如果需要对DTD进行语法分析,请使用可选的DeclHandler。

DeclHandler是SAX的扩展。不是所有的语法分析器都支持它。

EntityResolver:定义与装入实体关联的事件。只有少数几个应用程序注册这些事件。

ErrorHandler:定义错误事件。许多应用程序注册这些事件以便用它们自己的方式报错。

DefaultHandler:它提供了这些接LI的缺省实现。在大多数情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现一个接口更容易。

下面是部分说明:

Android中的xml解析

SAX处理器说明


Android中的xml解析

部分常用方法说明

所以,我们通常要使用XmlReader和DefaultHandler配合起来解析xml文档。

SAX的解析流程:

startDocument --> startElement --> characters --> endElement --> endDocument


3、pull解析

Pull内置于Android系统中。也是官方解析布局文件所使用的方式。Pull与SAX有点类似,都提供了类似的事件,如开始元素和结束元素。不同的是,SAX的事件驱动是回调相应方法,需要提供回调的方法,而后在SAX内部自动调用相应的方法。而Pull解析器并没有强制要求提供触发的方法。因为他触发的事件不是一个方法,而是一个数字。它使用方便,效率高。Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。

pull返回的常量:

读取到xml的声明返回 START_DOCUMENT;

读取到xml的结束返回 END_DOCUMENT ;

读取到xml的开始标签返回 START_TAG;

读取到xml的结束标签返回 END_TAG;

读取到xml的文本返回 TEXT;

pull的工作原理:pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。

常用的XML pull的接口和类:

XmlPullParser:XML pull解析器是一个在XMLPULL VlAP1中提供了定义解析功能的接口。

XmlSerializer:它是一个接口,定义了XML信息集的序列。

XmlPullParserFactory:这个类用于在XMPULL V1 API中创建XML Pull解析器。

XmlPullParserException:抛出单一的XML pull解析器相关的错误。

pull的解析流程:

start_document --> end_document --> start_tag -->end_tag


在Android中还有第四种方式:android.util.Xml类 (本人未使用过)

在Android API中,另外提供了Android.util.Xml类,同样可以解析XML文件,使用方法类似SAX,也都需编写Handler来处理XML的解析,但是在使用上却比SAX来得简单 ,如下所示:

以android.util.XML实现XML解析

MyHandler myHandler=new MyHandler0;

android.util.Xm1.parse(url.openC0nnection().getlnputStream(),Xml.Encoding.UTF-8,myHandler);


三、实践

1、首先建立一个参考xml文档 (放在了assets目录中)


灵渠在广西壮族自治区兴安县境内,是世界上最古老的运河之一,有着“世界古代水利建筑明珠”的美誉。灵渠古称秦凿渠、零渠、陡河、兴安运河,于公元前214年凿成通航,距今已2217年,仍然发挥着功用。

http://imgsrc.baidu.com/baike/pic/item/389aa8fdb7b8322e08244d3c.jpg


胶莱运河南起黄海灵山海口,北抵渤海三山岛,流经现胶南、胶州、平度、高密、昌邑和莱州等,全长200公里,流域面积达5400平方公里,南北贯穿山东半岛,沟通黄渤两海。胶莱运河自平度姚家村东的分水岭南北分流。南流由麻湾口入胶州湾,为南胶莱河,长30公里。北流由海仓口入莱州湾,为北胶莱河,长100余公里。

http://imgsrc.baidu.com/baike/pic/item/389aa8fdb7b8322e08244d3c.jpg

位于淮河下游江苏省北部,西起洪泽湖边的高良涧,流经洪泽,青浦、淮安,阜宁、射阳,滨海等六县(区),东至扁担港口入海的大型人工河道。全长168km。

http://imgsrc.baidu.com/baike/pic/item/389aa8fdb7b8322e08244d3c.jpg


我们需要用一个River对象来保存数据,方便观察节点信息,抽象出River类

public class River {

String name;// 名称

Integer length;// 长度

String introduction;// 介绍

String Imageurl;// 图片url

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getLength() {

return length;

}

public void setLength(Integer length) {

this.length = length;

}

public String getIntroduction() {

return introduction;

}

public void setIntroduction(String introduction) {

this.introduction = introduction;

}

public String getImageurl() {

return Imageurl;

}

public void setImageurl(String imageurl) {

Imageurl = imageurl;

}

@Override

public String toString() {

return "River [name=" + name + ", length=" + length + ", introduction="

+ introduction + ", Imageurl=" + Imageurl + "]";

}

}


采用DOM解析时具体处理步骤是:

1 首先利用DocumentBuilderFactory创建一个DocumentBuilderFactory实例

2 然后利用DocumentBuilderFactory创建DocumentBuilder

3 然后加载XML文档(Document),

4 然后获取文档的根结点(Element),

5 然后获取根结点中所有子节点的列表(NodeList),

6 然后使用再获取子节点列表中的需要读取的结点。


下面我们就开始读取xml文档对象,并添加进List中:

代码如下: 我们这里是使用assets中的river.xml文件,那么就需要读取这个xml文件,返回输入流。 读取方法为:inputStream=this.context.getResources().getAssets().open(fileName); 参数是xml文件路径,当然默认的是assets目录为根目录。

然后可以用DocumentBuilder对象的parse方法解析输入流,并返回document对象,然后再遍历doument对象的节点属性。


/** * DOM解析xml方法

* @param filePath

* @return

*/

private ListDOMfromXML(String filePath) {

ArrayListlist = new ArrayList();

DocumentBuilderFactory factory = null;

DocumentBuilder builder = null;

Document document = null;

InputStream inputStream = null;

//构建解析器

factory = DocumentBuilderFactory.newInstance();

try {

builder = factory.newDocumentBuilder();

//找到xml文件并且加载

inputStream = this.getResources().getAssets().open(filePath);//getAssets后默认根目录为assets

document = builder.parse(inputStream);

//找到根Element

Element root=document.getDocumentElement();

NodeList nodes=root.getElementsByTagName(RIVER);

//遍历根节点所有子节点,rivers 下所有river

River river = null;

for (int i = 0; i < nodes.getLength(); i++) {

river = new River();

//获取river元素节点

Element riverElement = (Element) nodes.item(i);

//设置river中name和length属性值

river.setName(riverElement.getAttribute("name"));

river.setLength(Integer.parseInt(riverElement.getAttribute("length")));

//获取子标签

Element introduction = (Element) riverElement.getElementsByTagName(INTRODUCTION).item(0);

Element imageurl = (Element) riverElement.getElementsByTagName(IMAGEURL).item(0);

//设置introduction和imageurl属性

river.setIntroduction(introduction.getFirstChild().getNodeValue());

river.setImageurl(imageurl.getFirstChild().getNodeValue());

list.add(river);

}

} catch (ParserConfigurationException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (SAXException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

for (River river : list) {

Log.w("DOM Test", river.toString());

}

return list;

}

在这里添加到List中, 然后我们使用log将他们打印出来。如图所示:

Android中的xml解析

XML解析结果


采用SAX解析时具体处理步骤是:

1 创建SAXParserFactory对象

2 根据SAXParserFactory.newSAXParser()方法返回一个SAXParser解析器

3 根据SAXParser解析器获取事件源对象XMLReader

4 实例化一个DefaultHandler对象

5 连接事件源对象XMLReader到事件处理类DefaultHandler中

6 调用XMLReader的parse方法从输入源中获取到的xml数据

7 通过DefaultHandler返回我们需要的数据集合。

代码如下:


/**

* SAX解析xml

* @param filePath

* @return

*/

private ListSAXfromXML(String filePath) {

ArrayListlist = new ArrayList();

//构建解析器

SAXParserFactory factory = SAXParserFactory.newInstance();

SAXParser parser = null;

XMLReader xReader = null;

try {

parser = factory.newSAXParser();

//获取数据源

xReader = parser.getXMLReader();

//设置处理器

RiverHandler handler = new RiverHandler();

xReader.setContentHandler(handler);

//解析xml文件

xReader.parse(new InputSource(this.getAssets().open(filePath)));

list = handler.getList();

} catch (ParserConfigurationException e) {

e.printStackTrace();

} catch (SAXException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

for (River river : list) {

Log.w("DOM Test", river.toString());

}

return list;

}

以上就是Android中的xml解析的详细内容,更多请关注其它相关文章!