您的位置:首页 > 移动开发 > Android开发

android解析XML总结(SAX、Pull、Dom三种方式)附带DOM4J、JDOM

2012-10-09 23:56 816 查看
摘要: 在android开发中,经常用到去解析xml文件,常见的解析xml的方式有一下三种:SAX、Pull、Dom解析方式。最近做了一个android版的CSDN阅读器,用到了其中的两种(sax,pull),今天对android解析xml的这三种方式进行一次 ...

android开发中,经常用到去解析xml文件,常见的解析xml的方式有一下三种:SAX、Pull、Dom解析方式。最近做了一个android版的CSDN阅读器,用到了其中的两种(sax,pull),今天对android解析xml的这三种方式进行一次总结。

今天解析的xml示例(channels.xml)如下:

<?xml version="1.0" encoding="utf-8"?>
<channel>
<item id="0" url="http://www.baidu.com">百度item>
<item id="1" url="http://www.qq.com">腾讯item>
<item id="2" url="http://www.sina.com.cn">新浪item>
<item id="3" url="http://www.taobao.com">淘宝item>
channel>


一、使用sax方式解析

基础知识:

这种方式解析是一种基于事件驱动的api,有两个部分,解析器和事件处理器,解析器就是XMLReader接口,负责读取XML文档,和向事件处理器发送事件(也是事件源),事件处理器ContentHandler接口,负责对发送的事件响应和进行XML文档处理。

下面是ContentHandler接口的常用方法

public abstract void characters (char[] ch, int start, int length)

这个方法来接收字符块通知,解析器通过这个方法来报告字符数据块,解析器为了提高解析效率把读到的所有字符串放到一个字符数组(ch)中,作为参数传递给character的方法中,如果想获取本次事件中读取到的字符数据,需要使用start和length属性。

public abstract void startDocument () 接收文档开始的通知

public abstract void endDocument () 接收文档结束的通知

public abstract void startElement (String uri, String localName, String qName, Attributes atts) 接收文档开始的标签

public abstract void endElement (String uri, String localName, String qName) 接收文档结束的标签

在一般使用中为了简化开发,在org.xml.sax.helpers提供了一个DefaultHandler类,它实现了ContentHandler的方法,我们只想继承DefaultHandler方法即可。

另外SAX解析器提供了一个工厂类:SAXParserFactory,SAX的解析类为SAXParser 可以调用它的parser方法进行解析。

看了些基础以后开始上代码吧(核心代码,下载代码在附件)

1 public class SAXPraserHelper extends DefaultHandler {
2
3     final int ITEM = 0x0005;
4
5     List list;
6     channel chann;
7     int currentState = 0;
8
9     public List getList() {
10         return list;
11     }
12
13     /*
14      * 接口字符块通知
15 */
16     @Override
17     public void characters(char[] ch, int start, int length)
18             throws SAXException {
19         // TODO Auto-generated method stub
20 // super.characters(ch, start, length);
21         String theString = String.valueOf(ch, start, length);
22         if (currentState != 0) {
23             chann.setName(theString);
24             currentState = 0;
25         }
26         return;
27     }
28
29     /*
30      * 接收文档结束通知
31 */
32     @Override
33     public void endDocument() throws SAXException {
34         // TODO Auto-generated method stub
35         super.endDocument();
36     }
37
38     /*
39      * 接收标签结束通知
40 */
41     @Override
42     public void endElement(String uri, String localName, String qName)
43             throws SAXException {
44         // TODO Auto-generated method stub
45         if (localName.equals("item"))
46             list.add(chann);
47     }
48
49     /*
50      * 文档开始通知
51 */
52     @Override
53     public void startDocument() throws SAXException {
54         // TODO Auto-generated method stub
55         list = new ArrayList();
56     }
57
58     /*
59      * 标签开始通知
60 */
61     @Override
62     public void startElement(String uri, String localName, String qName,
63             Attributes attributes) throws SAXException {
64         // TODO Auto-generated method stub
65         chann = new channel();
66         if (localName.equals("item")) {
67             for (int i = 0; i < attributes.getLength(); i++) {
68                 if (attributes.getLocalName(i).equals("id")) {
69                     chann.setId(attributes.getValue(i));
70                 } else if (attributes.getLocalName(i).equals("url")) {
71                     chann.setUrl(attributes.getValue(i));
72                 }
73             }
74             currentState = ITEM;
75             return;
76         }
77         currentState = 0;
78         return;
79     }
80 }


1 private List getChannelList() throws ParserConfigurationException, SAXException, IOException
2     {
3         //实例化一个SAXParserFactory对象
4         SAXParserFactory factory=SAXParserFactory.newInstance();
5         SAXParser parser;
6         //实例化SAXParser对象,创建XMLReader对象,解析器
7         parser=factory.newSAXParser();
8         XMLReader xmlReader=parser.getXMLReader();
9         //实例化handler,事件处理器
10         SAXPraserHelper helperHandler=new SAXPraserHelper();
11         //解析器注册事件
12         xmlReader.setContentHandler(helperHandler);
13         //读取文件流
14         InputStream stream=getResources().openRawResource(R.raw.channels);
15         InputSource is=new InputSource(stream);
16         //解析文件
17         xmlReader.parse(is);
18         return helperHandler.getList();
19     }


从第二部分代码,可以看出使用SAX解析XML的步骤:

1、实例化一个工厂SAXParserFactory

2、实例化SAXPraser对象,创建XMLReader 解析器

3、实例化handler,处理器

4、解析器注册一个事件

5、读取文件流

6、解析文件

或者以下一种理解:

》Sax定义

SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于android等移动设备

SAX全称是Simple API for Xml,既是指一种接口,也是一个软件包

作为接口,sax是事件驱动型xml解析的一个标准接口

》Sax特点

1. 解析效率高,占用内存少

2.可以随时停止解析

3.不能载入整个文档到内存

4.不能写入xml

5.SAX解析xml文件采用的是事件驱动

---sax并不需要解析完 整个文档,在按内容顺序解析文档的过程中,sax会判断当前读到的字符是否合法xml语法中的某部分,如果符合就会触发事件

》Sax工作原理

Sax的工作原理简单的说,就是对文档进行顺序扫描,扫描到文档(document)开始与结束,扫描到元素(element)开始、结束等地方时调用事件处理

处理函数做相应动作,然后继续扫描,直到文档结束。

二、使用pull方式解析

基础知识:

android系统中,很多资源文件中,很多都是xml格式,在android系统中解析这些xml的方式,是使用pul解析器进行解析的,它和sax解析一样(个人感觉要比sax简单点),也是采用事件驱动进行解析的,当pull解析器,开始解析之后,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。

其实以上描述,就是对整个解析步骤的一个描述,看看代码吧

1 private List<map> getData() {
2         List<map> list = new ArrayList<map>();
3         XmlResourceParser xrp = getResources().getXml(R.xml.channels);
4
5         try {
6             // 直到文档的结尾处
7             while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
8                 // 如果遇到了开始标签
9                 if (xrp.getEventType() == XmlResourceParser.START_TAG) {
10                     String tagName = xrp.getName();// 获取标签的名字
11                     if (tagName.equals("item")) {
12                         Map map = new HashMap();
13                         String id = xrp.getAttributeValue(null, "id");// 通过属性名来获取属性值
14                         map.put("id", id);
15                         String url = xrp.getAttributeValue(1);// 通过属性索引来获取属性值
16                         map.put("url", url);
17                         map.put("name", xrp.nextText());
18                         list.add(map);
19                     }
20                 }
21                 xrp.next();// 获取解析下一个事件
22             }
23         } catch (XmlPullParserException e) {
24             // TODO Auto-generated catch block
25             e.printStackTrace();
26         } catch (IOException e) {
27             // TODO Auto-generated catch block
28             e.printStackTrace();
29         }
30
31         return list;
32     }


或者以下一种理解:

》pull解析器简介

1.pull解析器是android内置的解析器,解析原理与sax类似

2.pull它提供了类似的事件。

如:开始元素和结束元素事件,使用parse.next()可以进入下一个元素并触发相应的事件,事件将作为数值代码被发送

因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法获取下一个Text类型节点的值

》pull与sax的不同之处

1.pull读取xml文件后触发相应的事件调用方法返回的是数字。

2.pull可以在程序中控制,想解析到哪里就可以停止到哪里

3.Android中更推荐使用pull解析

》pull解析步骤

1.创建解析器对象

XmlPullParser paser = Xml.newPullParser();

2.进行解析

paser.setInput(input,"utf-8");

3.产生第一个解析事件

int eventType = paser.getEventType();

4.可以使用循环判断是否继续解析

while(eventType!=XmlPullParser.END_DOCUMENT){}

三、使用Dom方式解析

基础知识:

最后来看看Dom解析方式,这种方式解析自己之前也没有用过(在j2ee开发中比较常见,没有做过这方面的东西),在Dom解析的过程中,是先把dom全部文件读入到内存中,然后使用dom的api遍历所有数据,检索想要的数据,这种方式显然是一种比较消耗内存的方式,对于像手机这样的移动设备来讲,内存是非常有限的,所以对于比较大的XML文件,不推荐使用这种方式,但是Dom也有它的优点,它比较直观,在一些方面比SAX方式比较简单。在xml文档比较小的情况下也可以考虑使用dom方式。

Dom方式解析的核心代码如下:

1 public static List getChannelList(InputStream stream)
2     {
3         List list=new ArrayList();
4
5         //得到 DocumentBuilderFactory 对象, 由该对象可以得到 DocumentBuilder 对象
6         DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
7
8         try {
9             //得到DocumentBuilder对象
10             DocumentBuilder builder=factory.newDocumentBuilder();
11             //得到代表整个xml的Document对象
12             Document document=builder.parse(stream);
13             //得到 "根节点"
14             Element root=document.getDocumentElement();
15             //获取根节点的所有items的节点
16             NodeList items=root.getElementsByTagName("item");
17             //遍历所有节点
18             for(int i=0;i<items.getlength();i++)
19             {
20                 channel chann=new channel();
21                 Element item=(Element)items.item(i);
22                 chann.setId(item.getAttribute("id"));
23                 chann.setUrl(item.getAttribute("url"));
24                 chann.setName(item.getFirstChild().getNodeValue());
25                 list.add(chann);
26             }
27
28         } catch (ParserConfigurationException e) {
29             // TODO Auto-generated catch block
30             e.printStackTrace();
31         } catch (SAXException e) {
32             // TODO Auto-generated catch block
33             e.printStackTrace();
34         } catch (IOException e) {
35             // TODO Auto-generated catch block
36             e.printStackTrace();
37         }
38
39         return list;
40     }


总结一下Dom解析的步骤(和sax类似)

1、调用 DocumentBuilderFactory.newInstance() 方法得到 DOM 解析器工厂类实例。

2、调用解析器工厂实例类的 newDocumentBuilder() 方法得到 DOM 解析器对象

3、调用 DOM 解析器对象的 parse() 方法解析 XML 文档得到代表整个文档的 Document 对象。

或者以下一种理解:

》DOM简介

dom全称Document Object Model ,为xml文档的已解析版本定义了一组接口。解析器读入整个文档,然后构建一个主流内存的树结构,

然后代码就可以使用dom接口来操作这个树结构

》DOM的特点

>优点

1.整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能

2.通过树形结构存取xml文档

3.可以在树的某个节点上向前或向后移动

>缺点

1.将整个文档调入内存(包括无用的节点),浪费时间和空间

>适用场合

一旦解析了文档还需多次访问这些数据;硬件资源充足(内存,cpu)

》DOM解析步骤

1.创建解析器工厂

2.获得解析器工厂

3.接受一个xml文档作为输入参数名,并得到一个xml的文档对象(Document)

4.操作文档对象

四、使用JDOM方式解析

基础知识:

JDOM是处理xml的纯java api.使用具体类而不是接口.JDOM具有树的遍历,又有SAX的java规则.

优点:是基于树的处理xml的java api,把树加载到内存中.

没有向下兼容的限制,所以比DOM简单.

速度快.

具有SAX的java 规则.

缺点:不能处理大于内存的文档.

JDOM表示XML文档逻辑模型,不能保证每个字节真正变换.

针对实例文档不提供DTD与模式的任何实际模型.

不支持于DOM中相应遍历包.

、使用DOM4J方式解析

基础知识:

dom4j有更复杂的api,所以dom4j比jdom有更大的灵活性.

六、总结

除以上三种外还有很多解析xml的方法,比如DOM4J、JDOM等等。但其基本的解析方式包含两种,一种是事件驱动的(代表SAX),另一种方式是基于文档结构(代表DOM)。其他的只不过语法不一样而已。

附(本文示例运行截屏):



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: