xml数据解析
来源:互联网 发布:转运物品 淘宝 编辑:程序博客网 时间:2024/06/07 17:16
5.1.2结构性的文件—读写XML文件
通过上面的介绍我们可以自由的操作Android中普通的文本文件了,下面我们来介绍下android中比较常用的结构性的文件—XML文件。
XML,可扩展标记语言(Extensible Markup Language),用于标记电子文件,使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。
AndroidSDK提供了如下package来支持XML的读写:
l javax.xml 根据XML规范定义核心XML常量和功能。
l javax.xml.parsers 提供DOM和SAX方法解析XML文档。
l org.w3c.dom W3C提供的使用DOM方法读取XML。
l org.xml.sax 提供核心SAX APIs。
l org.xmlpull.v1 PULL解析器。
后面三个包中分别是android自带的三个XML解析器,有PULL、SAX(Simple API for XML)、DOM解析器。其中PULL跟SAX都是以事件作为驱动导向的解析器,优点是占用内存小,处理速度快。DOM是将整个XML放入内存中再解析,处理速度要稍差一些,但DOM也有自己的优点,可以在解析的时候适当增加节点。
在这里对这3种方法分别加以说明。
首先我们来看看我们需要解析的示例XML文档:
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id = "1">
<name>小王</name>
<age>20</age>
</person>
<person id = "2">
<name>小明</name>
<age>30</age>
</person>
<person id = "3">
<name>小丽</name>
<age>40</age>
</person>
</persons>
然后我们在代码中创建一个与XML子节点对应的模型类。
public class Person {
protected String id;
protected String name;
protected String age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
下面我们就将对这个XML用不同的方法来解析。
先来看如何采用DOM方式进行解析。
采用DOM的方法,读取XML文档的思路,这基本上与XML的结构是完全一样的。首先加载XML文档(Document),然后获取文档的根结点(Element),然后获取根结点中所有子节点的列表(NodeList),然后使用再获取子节点列表中的需要读取的结点。
根据以上思路,简要写个读取XML文件的方法如下:
1)实现DomHandler。
// import略
public class DomHandler {
private InputStream input;
private List<Person> persons;
private Person person;
public DomHandler() {
}
public DomHandler(InputStream input) {
this.input = input;
}
public void setInput(InputStream input) {
this.input = input;
}
public List<Person> getPersons(){
persons = new ArrayList<Person>();
DocumentBuilder builder = null;
Document document = null;
try {
// 通过Dom工厂方法建立Dom解析器
builder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
document = builder.parse(input);
Element element = document.getDocumentElement();
// 取得节点<person>的节点列表
NodeList personNodes =element.getElementsByTagName("person");
// 节点长度
int length = personNodes.getLength();
for(int i = 0; i < length; i++){
// 取得<person>的节点元素
Element personElement = (Element)personNodes.item(i);
person = new Person();
// 取得<person id="1">中的id属性值
person.setId(personElement.getAttribute("id"));
// 继续向下,取得子节点列表,如<name><age>等等
NodeList childnodes = personElement.getChildNodes();
int len = childnodes.getLength();
for(int j = 0 ; j < len ; j++){
// 如果子节点是一个元素节点
if(childnodes.item(j).getNodeType() == Node.ELEMENT_NODE){
// 取得节点名称
String nodeName = childnodes.item(j).getNodeName();
// 取得节点值
String nodeValue =
childnodes.item(j).getFirstChild().getNodeValue();
if("name".equals(nodeName)){
person.setName(nodeValue);
}
if("age".equals(nodeName)){
person.setAge(nodeValue);
}
}
}
persons.add(person);
}
return persons;
} catch (Exception e) {
e.printStackTrace();
} finally {
document = null;
builder = null;
}
return null;
}
}
2)使用DomHandler进行解析。
public static List<Person> readXMLByDOM(String filePath) {
try {
FileInputStream fis = new FileInputStream(new File(filePath));
DomHandler domHandler = new DomHandler(fis);
return domHandler.getPersons();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
以上就是使用DOM方式解析XML文件的方法。
下面我们介绍如何采用SAX的方法对XML文件进行读取。
SAX采用基于事件驱动的处理方式,它将XML文档转换成一系列的事件,由单独的事件处理器来决定如何处理。为了了解如何使用SAXAPI处理XML文档,这里介绍一下SAX所使用的基于事件驱动的处理方式。
基于事件的处理方式主要围绕着事件源以及事件处理器来工作的。一个可以产生事件的对象被称为事件源,而可以对事件产生响应的对象就被叫做事件处理器 。事件源与事件处理对象是通过在事件源中的事件注册方法连接的。当事件源产生事件后,调用事件处理器相应的方法,一个事件获得处理。当在事件源调用事件处理器中特定方法的时候,会传递这个事件标志以及其响应事件的状态信息,这样事件处理器才能够根据事件信息来决定自己的行为。
在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法来开始解析XML文档,并根据文档的内容产生事件。而事件处理器则是org.xml.sax包中的ContentHander、DTDHander、ErrorHandler,以及 EntityResolver这4个接口,它们分别处理事件源在解析XML文档过程中产生的不同种类的事件。而事件源XMLReader与这4个事件处理器的连接是通过在XMLReader中的相应事件处理器注册方法setXXXX()来完成的,详细介绍请见表5-1所示。
处理器名称
处理事件
XMLReader注册方法
ContentHandler
跟文档内容有关的事件
1)文档的开始与结束
2)xml元素的开始与结束
3)可忽略的实体
4)名称空间前缀映射的开始和结束
5)处理指令
6)字符数据和可忽略的空格
setContentHandler(ContentHandler h)
ErrorHandler
处理XML文档时产生的错误
setErrorHandler(ErrorHandler h)
DTDHandler
处理对文档的DTD进行解析时产生的事件
setDTDHandler(DTDHandler h)
EntityResolover
处理外部实体
setEntityResolover(EntityResolover h)
表5-1 事件处理器介绍
以上的4个事件源处理器接口,在开发中没有必要直接从这4个接口直接继承,因为org.xml.sax.helper包为我们提供了类 DefaultHandler,其继承了这4个接口,在实际开发中直接从DefaultHandler继承并实现相关方法就可以了。
在这4个接口中,最重要的是ContentHanlder接口,下面就其中的方法加以说明,如下:
1)startDocument()
当遇到文档开始的时候,调用这个方法,可以在其中做一些预处理的工作。
2)endDocument()
与遇到文档开始的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。
3) startElement(String namespaceURI, String localName, String qName,Attributes atts)
当读到一个开始标签的时候,会触发这个方法。namespaceURI就是命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名。通过atts可以得到所有的属性名和相应的值。要注意的是SAX中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会纪录下以前所碰到的标签,也就是说,在startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元属等等其它与结构相关的信息,都是不得而知的,都需要我们的程序来完成。这使得SAX在编程处理上没有DOM来得那么方便。
4)endElement(String uri, String localName, String name)
同理,在遇到结束标签的时候,调用这个方法。
5)characters(char[] ch, int start, int length)
这个方法用来处理在XML文件中读到的内容,第一个参数为文件的字符串内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。
只要为SAX提供实现ContentHandler接口的类,那么该类就可以得到通知事件(实际上就是SAX调用了该类中的回调方法)。因为ContentHandler是一个接口,在使用的时候可能会有些不方便,因此,SAX还为其制定了一个Helper类:DefaultHandler,它实现了ContentHandler接口,但是其所有的方法体都为空,在实现的时候,你只需要继承这个类,然后重载相应的方法即可。
使用SAX解析android.xml的代码如下:
1)实现DefaultHandler接口。
// import略
public class SaxHandler extends DefaultHandler {
private List<Person> persons;
private Person person;
// tagName的作用是记录解析时的上一个节点名称
private String tagName;
public List<Person> getPersons(){
return persons;
}
/**
* 节点处理
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException
{
String data = new String(ch, start, length);
if("name".equals(tagName)){
person.setName(data);
}
if("age".equals(tagName)){
person.setAge(data);
}
}
/**
* 元素结束
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("person".equals(localName)){
persons.add(person);
person = null;
}
tagName = null;
}
/**
* 文档开始
*/
@Override
public void startDocument() throws SAXException {
persons = new ArrayList<Person>();
}
/**
* 元素开始
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if("person".equals(localName)){
person = new Person();
person.setId(attributes.getValue("id"));
}
// 将正在解析的节点名称赋给tagName
tagName = localName;
}
}
2)使用SaxHandler进行解析。
public static List<Person> readXMLBySAX(String file_path) {
try {
FileInputStream fis = new FileInputStream(new File(file_path));
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
SaxHandler saxHandler = new SaxHandler();
parser.parse(fis, saxHandler);
return saxHandler.getPersons();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
下面继续介绍如何使用Pull方式实现XML文件的解析。
Pull解析器是一个开源的Java项目,Android系统内部解析XML文件均为此种方式。Pull 解析器的运行方式与SAX解析器相似,它提供了类似的事件(开始元素和结束元素),但我们需要使用parser.next()提取它们。事件将作为数值代码被发送,因此可以使用一个简单case-switch语句来实现。
1)实现解析类。
// import略
public class PullHandler {
private InputStream input;
private List<Person> persons;
private Person person;
public PullHandler() {
}
public void setInput(InputStream input) {
this.input = input;
}
public PullHandler(InputStream input) {
this.input = input;
}
public List<Person> getPersons() {
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(input, "UTF-8");
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
// 表示开始文档事件
persons = new ArrayList<Person>();
break;
case XmlPullParser.START_TAG:
// 开始标签
// parser.getName()获取节点的名称
String tag = parser.getName();
if ("person".equals(tag)) {
person = new Person();
// 取得第一个属性值
String id = parser.getAttributeValue(0);
person.setId(id);
}
if (null != person) {
if ("name".equals(tag)) {
// 获取下一个text类型的节点
person.setName(parser.nextText());
}
if ("age".equals(tag)) {
person.setAge(parser.nextText());
}
}
break;
case XmlPullParser.END_TAG:
// XmlPullParser.END_TAG:结束标签
if ("person".equals(parser.getName())) {
persons.add(person);
person = null;
}
break;
}
// 继续下一个元素
eventType = parser.next();
}
input.close();
return persons;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
2)使用PullHandler进行解析。
public static List<Person> readXMLByPULL(String file_path) {
try {
FileInputStream fis = new FileInputStream(new File(file_path));
PullHandler pullHandler = new PullHandler(fis);
return pullHandler.getPersons();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
经验分享:
如何在实际项目中选用DOM、SAX还是PULL方式,要根据具体的项目情况来决定。以下介绍下三种方式各自的优缺点及使用场合,开发者可以根据项目的具体情况做判断。
DOM(文档对象模型),为XML文档的解析定义了一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,然后代码就可以使用DOM接口来操组整个树结构,具体分析如下:
优点:整个文档树都在内存当中,便于操作;支持删除、修改、重新排列等多功能。
缺点:将整个文档调入内存(经常包含大量无用的节点),浪费时间和空间。
使用场合:一旦解析了文档还需要多次访问这些数据,而且资源比较充足(如内存、CPU等)。
为了解决DOM解析XML引起的这些问题,出现了SAX。
SAX解析XML文档为事件驱动,详细说明请阅读Android读写XML(中)–SAX 。当解析器发现元素开始、元素结束,文本、文档的开始或者结束时,发送事件,在程序中编写响应这些事件的代码,其特点如下:
优点:不用事先调入整个文档,占用资源少。尤其在嵌入式环境中,极力推荐采用SAX进行解析XML文档。
缺点:不像DOM一样将文档长期驻留在内存,数据不是持久的,事件过后,如没有保存数据,那么数据就会丢失。
使用场合:机器性能有限,尤其是在嵌入式环境,如Android,极力推荐采用SAX进行解析XML文档。
大多数时间,使用SAX是比较安全的,并且Android提供了一种传统的SAX使用方法,以及一个便捷的SAX包装器。如果XML文档比较小,那么DOM可能是一种比较简单的方法。如果XML文档比较大,但只需要文档的一部分,则XML Pull解析器可能是更为有效的方法。最后对于编写XML,Pull解析器包也提供了一种便捷的方法。
原文
- oracle解析xml数据
- 解析XML格式数据
- Jdom 解析XML数据
- jquery 解析 xml数据
- xml数据解析
- xml数据的解析
- Android---解析XML数据
- xml形式数据解析
- xml数据解析
- XML数据解析
- js解析XML数据
- 解析XML数据
- iOS xml数据解析
- 解析XML数据
- xml数据解析
- XML数据的解析
- xml数据解析方法
- XML、JSON数据解析
- 这里没有“软文黑稿”,给你看纯正独立的分享文章
- Thinkphp3.2.3登录页面验证码非正常显示
- C/C++种字符串的安全操作方式strcpy_s等字符串处理函数
- 如何解决Android 5.0中出现的警告:Service Intent must be explicit
- VirtualBox 配置虚拟网卡(桥接),实现主机-虚拟机网络互通
- xml数据解析
- Docker相关文章索引(3)
- TortoiseGit学习笔记(三)
- jQuery动画---显示、卷动、淡入淡出
- ARC forbids explicit message sendof'dealloc'
- var let 和const
- NGUI文字闪烁效果
- linux信号量
- 清除win+r的记录