PULL解析简单易上手,基本上看一遍,基本上就会解析啦,但总是感觉对PULL解析的运行机制不是很了解,就总结了以下事件驱动到底是怎么执行的。。

PULL: Android内置了PULL解析器。PULL解析器与SAX解析器类似,它提供了类似的事件,例如,开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发事件。每一种事件将作为数值代码被传送,因此使用一个switch来对感兴趣的事件进行处理。 
这也是我最喜欢的方法,简单好用。 
下面将对解析过程进行详细介绍,它到底是怎么运行的呢。 
这是XML Pull Parsing官网:http://www.xmlpull.org/ 里边有详细的解析。

一、XmlPullParser 常见事件:

START_DOCUMENT: 文档开始 
START_TAG : 标签开始 
TEXT : 文本 
END_DOCUMENT:文档结束 
END_TAG:标签结束 
CDSECT :CDATA sections was just read (this token is available only from nextToken()) 
在标记CDATA下,所有的标记、实体引用都被忽略,而被XML处理程序一视同仁地当做字符 数据看待,CDATA的形式如下:

<![CDATA[文本内容]]>
CDATA的文本内容中不能出现字符串“]]>”

  

,另外,CDATA不能嵌套。 
COMMENT :注释 
DOCDECL: 就是

<DOCTYPE 

IGNORABLE_WHITESPACE :可忽略的空白。在没用dtd约束文档时, IGNORABLE_WHITESPACE只会出现在根元素外面;对于有dtd约束的文档,空白由dtd约束文档定义。(dtd约束文档就是在DOCTYPE中指定的那个文件,它规定了可以在xml出现什么标签、以及标签可以出现在哪等) 
。。。。 
常有的标签就5个:START_DOCUMENT ,START_TAG, TEXT, END_DOCUMENT , END_TAG。

二、一些比较重要复杂的常见方法:结合源代码解析

1) int nextTag():

Call next() and return event if it is START_TAG or END_TAG otherwise throw an exception. It will skip whitespace TEXT before actual tag if any. 
//调用next()返回START_TAG or END_TAG这两个事件,其他抛出异常。它会跳过空白text 
本质执行过程就是这样: 
int eventType = next(); 
if(eventType == TEXT && isWhitespace()) { // skip whitespace 
eventType = next(); 

if (eventType != START_TAG && eventType != END_TAG) { 
throw new XmlPullParserException(“expected start or end tag”, this, null); 

return eventType;

2) String nextText():

If current event is START_TAG then if next element is TEXT then element content is returned or if next event is END_TAG then empty string is returned, otherwise exception is thrown. After calling this function successfully parser will be positioned on END_TAG. 
//当前事件是START_TAG,下一元素是text就返回它的内容,或下一个事件是END_TAG那么返回空字符串“”,其他抛出异常。调用完这个函数事件定位在END_TAG。 
The motivation for this function is to allow to parse consistently both empty elements and elements that has non empty content, for example for input:

<tag>foo</tag><tag></tag> (which is equivalent to both input can be parsed with the same code:

3. p.nextTag()
4. p.requireEvent(p.START_TAG, “”, “tag”);
5. String content = p.nextText();
6. p.requireEvent(p.END_TAG, “”, “tag”);

This function together with nextTag make it very easy to parse XML that has no mixed content. 
本质执行过程就是这样:

if(getEventType() != START_TAG) {
throw new XmlPullParserException(
“parser must be on START_TAG to read next text”, this, null);
}
int eventType = next();
if(eventType == TEXT) {
String result = getText();
eventType = next();
if(eventType != END_TAG) {
throw new XmlPullParserException(
“event TEXT it must be immediately followed by END_TAG”, this, null);
}
return result;
} else if(eventType == END_TAG) {
return “”;
} else {
throw new XmlPullParserException(
“parser must be on START_TAG or TEXT to read text”, this, null);
}

3)int nextToken():

This method works similarly to next() but will expose additional event types (COMMENT, CDSECT, DOCDECL, ENTITY_REF, PROCESSING_INSTRUCTION, or IGNORABLE_WHITESPACE) if they are available in input. 
//这个方法和next()相似,但是会揭露其他事件类型,例如:COMMENT, CDSECT, DOCDECL, ENTITY_REF, PROCESSING_INSTRUCTION, or IGNORABLE_WHITESPACE。如果它们在输入中。 
即它可以返回所有的事件类型:空白,注释,CDSECT。。等等 
注释太多,而且不常用,想研究的自己看源代码吧。

4)public int next()

//返回下一个解析事件 
Get next parsing event - element content wil be coalesced and only one TEXT event must be returned for whole element content (comments and processing instructions will be ignored and emtity references must be expanded or exception mus be thrown if entity reerence can not be exapnded). If element content is empty (content is “”) then no TEXT event will be reported. 
**另:next()与nextToken()的区别: 
next:主要是用于返回比较高层的事件的。其中包括:START_TAG, TEXT, END_TAG, END_DOCUMENT 
nextToken():返回所有事件。 
While next() provides access to high level parsing events, nextToken() allows access to lower level tokens.

5) void require(int type,String namespace,String name)

Test if the current event is of the given type and if the 
namespace and name do match. null will match any namespace and any name. If the current event is TEXT with isWhitespace()= true, and the required type is not TEXT, next () is called prior to the test. 
//测试当前事件是给定事件类型。Namespace,name是null表示任意匹配。 
如果当前事件是Text且为空,required type不是text,那么就会调用next()

if (getEventType() == TEXT && type != TEXT && isWhitespace ())
next (); if (type != getEventType()
|| (namespace != null && !namespace.equals (getNamespace ()))
|| (name != null && !name.equals (getName ()))
throw new XmlPullParserException ( “expected “+ TYPES[ type ]+getPositionDesctiption());

三、解析过程讲解

(1) 创建PULL解析器 :两种方法实质一样: 
1.XmlPullParser parser = Xml.newPullParser(); 
2. XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser parser2 = factory.newPullParser(); 
(2)常用方法: 
void setInput(InputStream inputstream,string inputEncoding) 该方法设置需要解析的 xml数据流及编码。 
int getEventType() 该方法用来获得事件类型,例如START_DOCUMENT,END_DOCUMENT,START_TAG(标签开始),END_TAG(标签结束)等 
String getName() 获得标签名 
String getAttributeName(int index) 
String getAttributeValue(String namespace,String name) 这两个方法获得标签的属性,第一种方法是根据节点属性的序号来获取,第二种方法是根据节点的属性名来获取,参数namespace是命名空间,name是属性名。 
示例代码: 
这是android中的代码:

/**
* 读取RAW(在res文件夹下新建的)目录下的文件测试Pull解析xml文件
* START_DOCUMENT后是persons是START_TAG,后跟着是TEXT
* END_TAG后紧跟着是TEXT
* 如果当前标签是START_TAG,则getTExt()返回的是null
*/
private void getXmlData2(){
String tagname=null;
int m=0,n=0;
InputStream is = this.getResources().openRawResource(R.raw.test);//读取RAW(在res文件夹下新建的)目录下的test.xml文件
try {//创建XmlPullParser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = factory.newPullParser();
parser.setInput(is, "UTF-8");
int event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
switch (event) {
case XmlPullParser.START_DOCUMENT: //START_DOCUMENT后是persons是START_TAG,后跟着是TEXT
System.out.println("START_DOCUMENT");
break;
case XmlPullParser.TEXT:
if(m==1){
System.out.println("START_TAG后是TEXT");
m=0;
}
break;
case XmlPullParser.START_TAG: //标签开始
if("persons".equals(parser.getName())){
System.out.println("START_DOCUMENT后是START_TAG");
m++;
}
if ("person".equals(parser.getName())) {
for(int i=0;i<parser.getAttributeCount();i++)
System.out.println("id:"+parser.getAttributeValue(i));
}else if(("name").equals(parser.getName())){
//System.out.println("name:"+parser.getText());//null
tagname = parser.nextText();
System.out.println("name:"+tagname);
}else if("age".equals(parser.getName())){
tagname = parser.nextText();
System.out.println("age:"+tagname);
}
break;
case XmlPullParser.END_TAG:
if ("person".equals(parser.getName())) {
System.out.println("person标签结束");
}
break;
}
event = parser.next();
System.out.println("eventType:"+event);//2是START_TAG,4是TEXT
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }

  xml源文件:

<?xml version="1.0" encoding="UTF-8"?>

<persons>
<person id="0">
<name>张超</name>
<age>20</age>
</person>
<person id="1">
<name>小明</name>
<age>21</age>
</person>
</persons>

  解析过程:

在开始讲解执行过程之前,先说下每个标签的执行过程: 
1.START_TAG :标签开始 
2.TEXT :值 
3.END_TAG :标签结束 
4.TEXT : 对你没看错,这里也有一个TEXT,虽然我不知道它干嘛用的,但就是有。 
每个标签都是按这个过程执行的。好下面就这个例子详解: 
从图里可以看出执行过程: 
最开始是START_DOCUMENT,然后就到了<persons>标签,这时就像上边说的执行了: 
START_TAG,TEXT ,注意看图中的前五行(图中有一个错误第三行的‘也是’改为‘后是’,代码中已经改过来啦),evevtType=2(START_TAG)evevtType=4(TEXT),这时没有匹配的事件;就开始执行下一个:<person>标签,也是START_TAG后跟着TEXT,图中的6,7,8行,6行eventType=2,输出了属性id,紧跟着就是4(TEXT)。 
接下来是END_TAG ,TEXT 。图中的name=‘张超’结束后,紧跟着是4(TEXT)!!也就是</name>后又执行了个TEXT,接下来的2是<age>的开始事件。 
讲到这就应该很清楚啦,自己也可以试试,比如这么写:<name>小明</name>bbb 我已经试过啦,这个’bbb’是可以识别出来的,代码不难写加控制条件就能写出来,代码就不全贴啦,贴个代码片段:

if(n==1){
System.out.println("name后:"+parser.getText());
n=0;
}

3. 下面总结一下运行过程:

START_DOCUMENT ,START_TAG ,TEXT ,END_TAG,TEXT,START_TAG …… 
END_DOCUMENT 
就是这么执行的,总算搞定啦。。。。。。 
转发请注明出处:http://www.cnblogs.com/jycboy/
另推荐一个android xml解析博文,里边对XmlPullParser的方法讲的比较全,感兴趣的`可以去看看:http://yuanzhifei89.iteye.com/blog/1149151

PULL解析XML的运行机制详解的更多相关文章

  1. JavaScript运行机制详解

    JavaScript运行机制详解   var test = function(){ alert("test"); } var test2 = function(){ alert(& ...

  2. Linux find运行机制详解

    本文目录: 1.1 find基本用法示例 1.2 find理论部分 1.2.1 expression-operators 1.2.2 expression-options 1.2.3 expressi ...

  3. JavaScript 运行机制详解:再谈Event Loop

    原文地址:http://www.ruanyifeng.com/blog/2014/10/event-loop.html 一年前,我写了一篇<什么是 Event Loop?>,谈了我对Eve ...

  4. JavaScript 运行机制详解:深入理解Event Loop

    Philip Roberts的演讲<Help, I'm stuck in an event-loop>,详细.完整.正确地描述JavaScript引擎的内部运行机制. 一.为什么JavaS ...

  5. javascript运行机制详解: 再谈Event Loop(转)

    作者: 阮一峰 日期: 2014年10月 8日 一年前,我写了一篇<什么是 Event Loop?>,谈了我对Event Loop的理解. 上个月,我偶然看到了Philip Roberts ...

  6. 如何通过setTimeout理解JS运行机制详解

    setTimeout()函数:用来指定某个函数或某段代码在多少毫秒之后执行.它返回一个整数,表示定时器timer的编号,可以用来取消该定时器. 例子 ? 1 2 3 4 5 console.log(1 ...

  7. JavaScript 运行机制详解

    一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Java ...

  8. 【repost】JavaScript 运行机制详解:再谈Event Loop

    一年前,我写了一篇<什么是 Event Loop?>,谈了我对Event Loop的理解. 上个月,我偶然看到了Philip Roberts的演讲<Help, I'm stuck i ...

  9. [转] JavaScript 运行机制详解:再谈Event Loop

    一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Java ...

随机推荐

  1. CSS3 介绍

    什么是CSS3 CSS即层叠样式表(Cascading Stylesheet). 在网页制作时采用CSS技术,可以有效地对页面的布局.字体.颜色.背景和其它效果实现更加精确的控制. 只要对相应的代码做 ...

  2. HTML5 Web 客户端五种离线存储方式汇总

    最近折腾HTML5游戏需要离线存储功能,便把目前可用的几种HTML5存储方式研究了下,基于HT for Web写了个综合的实例,分别利用了Cookie.WebStorage.IndexedDB以及Fi ...

  3. Java魔法堂:URI、URL(含URL Protocol Handler)和URN

    一.前言 过去一直搞不清什么是URI什么是URL,现在是时候好好弄清楚它们了!本文作为学习笔记,以便日后查询,若有纰漏请大家指正! 二.从URI说起    1. 概念 URI(Uniform Reso ...

  4. [python基础]关于装饰器

    在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...

  5. Emit学习(3) - OpCodes - 循环和异常

    本来准备直接进入Dapper的, 但是昨天初步看了一下, 内容不少, Dapper不愧是一款成熟的框架, 里面对各种情况的考虑, 很实用, 不过这也使得我短时间内看不完, 所以得等几天了. 那就先来看 ...

  6. C#串口通信

    通过COM1发送数据,COM2接收数据.当COM2接收完本次发送的数据后,向COM1发送信息通知COM1本次数据已发完,COM1接到通知后,再发下一段数据.这样可以确保每次发送的数据都可以被正确接收. ...

  7. 【FTP】C# System.Net.FtpClient库连接ftp服务器(下载文件)

    如果自己单枪匹马写一个连接ftp服务器代码那是相当恐怖的(socket通信),有一个评价较高的dll库可以供我们使用. 那就是System.Net.FtpClient,链接地址:https://net ...

  8. 【处理手记】Configuration system failed to initialize异常的另类原因

    有个c#程序在某台电脑上,执行某个操作时,总是会报如图错误: 度娘一番,发现市面上常见的原因是配置文件中的特定节点的位置不对,或者配置文件损坏等等,而这个程序根本没有使用内置的配置文件方案,而是用的i ...

  9. mvc jquery 修改 viewbag

    [HttpGet]        public ActionResult Modify(int id)        {            Books mod=db.Books.Where(b = ...

  10. js定时器的使用(实例讲解)

    在javascritp中,有两个关于定时器的专用函数,分别为: 1.倒计定时器:timename=setTimeout("function();",delaytime);2.循环定 ...