Android常见三种XML解析方式(SAX,PULL,DOM)

Reinaldo01U 8年前
   <h3><strong>环境搭建:</strong></h3>    <p>首先我们需要一个测试用的XML文档,以及搭建本地服务器,这里使用的是Tomcat,来模仿手机从网络上获取xml文档的环境</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/84d65debce9898fa6797f87c0cab3906.png"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/3889318d33b8d73030bd4d17e006ba06.png"></p>    <p>在搭建好本地服务器以及部署文档后,我们开始在代码中启动线程去访问这个xml文档,在 Android模拟器中 localhost 的IP地址是 10.0.2.2, <strong>代码如下:</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4a01f7e7558b0dd15029685ed22e5869.png"></p>    <p>在 connection 调用 conncet 方法后 使用 getResponseCode 方法返回连接的状态,200的意思代表OK,我们常见的404 Not Found也是此类状态码(status code),接着获取连接的输入流 inputStream,我们的XML解析就从这个输入流开始</p>    <h3><strong>SAX解析:</strong></h3>    <p>SAX解析XML需要用到一个 org.xml.sax.helpers 包下的 DefaultHandler 类,我们需要自己创建一个类继承于 DefaultHandler ,实现其中我们需要的几个方法, <strong>我们先来看代码:</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/560c6e2d68b34c9d513c6b5ac2612d57.png"></p>    <p>我们从 SAXParserFactory 工厂方法中获取到 XMLReader 的实例,再实例化我们自己创建,继承于 DefaultHandler 的 SAXParseHandler 类,最后设置 reader 的Handler为我们自己创建的类,设置 reader 的解析的数据来源,接下来我们来看 SAX 解析 XML文档的过程。</p>    <p>SAX解析XML的过程就在我们创建的类 SAXParseHandler 中, <strong>先上代码:</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0a2a941843b68747e18ed6afcfcdf0f3.png"></p>    <p>代码中重写的五个方法从字面意思可以知道大致的作用,我们在代码中加入相应的 Log 调试输出语句,来看看SAX解析XML的过程。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8f429a453d0d689bcafdafd0ba3845f8.png"></p>    <p>结合我们的XML文档,可以看出SAX解析XML时,首先会回调 startDocument() 方法,结束整个文档的解析时会调用 endDocument() 方法,当遇到标签元素时,会调用 startElement()方法,这里我们打印出了此时解析的 nodeName,就是我们XML文档中的第一个标签元素 <apps> ,接着会调用 characters 方法,显示长度 length 为 1 ,输出内容还换行了,这是因为 <apps> 标签后面有一个换行符,接下来继续调用 characters 方法,是因为下一个元素标签 <app> 前面有四个空格符,length就是4。总结的规律就是遇到 <app><id> 此类标签时就会调用 startElement()方法,</app></id>此类标签时就调用 endElement()方法,遇到其他内容就会调用 characters 方法,摸清解析过程后,我们来获取 XML文档中我们想要的数据。</p>    <p>开始解析</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/f88f29faf5b48b8389b6ee9d0b847fef.png"></p>    <p>在 startDocument() 方法中初始化我们的三个 StringBuilder 来存储接着我们要获取的数据,接着在 startElement 方法中记录下 此时的 nodeName,也就是<id>还是<name>此类标签</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/4f8d703c588532704fabb1486c49983c.png"></p>    <p>我们知道一般在调用 startElement 方法后,比如解析到<id>标签后,nodeName值为 id ,就会调用 characters 方法获取 <id> 标签后的内容,代码通过 switch 以 nodeName 为条件,假如之前 startElement 方法 nodeName为 id,相应的就把接下来的 characters 方法获取的内容 append 到我们创建的对应 id 的 StringBuilder中。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4f954c81278e81bbc3204fef86a27a20.png"></p>    <p>最后在 endElement 方法中,如果 localName为 <app>,代表我们 app 标签里面的 <id> <name> <version> 已经解析完毕,将其打印出来,因为 characters 方法会把各种换行符也读取出来,所以这里用 trim 方法整理下内容,接着清空 StringBuilder ,进入下一个 <app></app>标签循环,直到文档全部解析完毕。</p>    <p>SAX解析XML大致过程就是这样,简单粗暴,代码逻辑也较为清晰,但一旦开始解析就会从头解析到尾,不能直接控制解析的步骤。</p>    <h3><strong>PULL解析:</strong></h3>    <p>PULL解析是Android官方推荐的XML解析方式,以事件驱动来解析XML,同样非常好用,先来看看接口 XmlPullParser 里面有哪些事件</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f3df9bf3acec8e3aafa8d791ddbc94c8.png"></p>    <p>从字面意思就可以看出代表什么事件,那怎么用呢, <strong>直接上代码:</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/449a41aaefe3a4f2ddeefa3fb1513f0d.png"></p>    <p>从 XmlPullParserFactory 类中得到 XmlPullParser 实例,通过setInput方法设置要解析的XML 输入流,getEventType方法返回当前解析XML文档的事件,在while循环中只要 eventType 不是 END_DOCUMENT就继续解析XML文档,通过 parser的 next() 方法获取下一个事件,这里我们同样用Log来看一下事件的变化。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/a8d454eca5c7120402b08e501ec68202.png"></p>    <p>EventType后面相应的数字和我们上面接口定义的事件的值是相匹配的,从日志可以看出,事件从 0 START_DOCUMENT 开始,接着是 START_TAG 和 TEXT 交错,对应 标签 和 标签后的内容,这里解析到</app> 标签才出现 END_TAG 事件,之前的</id> </name> 这些结束标签确没有响应 END_TAG 事件,这里搞不懂,但并不影响我们获取需要的数据。</p>    <p>通过 parser.getName() 方法获取 nodeName(当前标签的字符串),后面通过 switch(eventType) 当遇到 START_TAG 事件时判断此时的 nodeName 是否为我们需要的 id name version,如果是就获取该标签内的内容,当遇到 END_TAG 事件,判断 nodeName 是否为 app,如果是就打印出我们获取的数据。</p>    <p>PULL方式非常简洁方便,灵活,我们获取所需数据后若不用再解析可以很方便的停止解析,PULL是几种方式中优点最多的,Android官方也推荐此方法来解析XML。</p>    <h3><strong>DOM解析:</strong></h3>    <p>DOM解析是这几种方式中最复杂的一个,采用树形结构来管理XML文档,同时内存占用也较多,不推荐使用此方法,尤其是在大一点的XML文档中,但可以学习怎么用, <strong>我直接通过代码里的注释来解释该方式:</strong></p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/cc63fe063af03fe88f8e1f344fbd09de.png"></p>    <p>是不是看起来有点绕,有点晕,实操之后还是可以理解的,通过不断的归纳以及细分标签的内容,最后获取所需的数据。</p>    <h3><strong>总结:</strong></h3>    <p>通过对三种解析XML的方式实践练习后,发现SAX和PULL两种方式较为好用,PULL更佳。</p>    <p> </p>    <p>来自:http://www.jianshu.com/p/2fc35b926e73</p>    <p> </p>