一、绪论
上周工作需要了解项目的一些大体内容,结果在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并覆盖相关的方法要比直接实现一个接口更容易。
下面是部分说明:
所以,我们通常要使用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将他们打印出来。如图所示:
采用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;
}
Atas ialah kandungan terperinci Android中的xml解析. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!