android xml解析XmlPullParser的使用

xml相关参考  
xml规范: http://www.w3.org/TR/REC-xml/  
Xerces-J sax解析器的一篇教程: http://terpconnect.umd.edu/~zhangx/xml/html/xmlprog/xercessax/briefintro.html  

xml的组成:  
xml声明  
<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
version:xml的版本,一般都是1.0 
encoding:xml的使用的编码,一般都是UTF-8 
standalone:表示该文档是否依赖于其他的文档(即是否include了其他的文档)。include了就是no,没有时就是yes(默认是没有的)。 

DOCTYPE声明  
<!DOCTYPE yuan SYSTEM "DTDs/yuan.dtd"> 
文档声明引用的是文件时(这里就是DTDs/yuan.dtd)(相对路径、绝对路径或由url标识指定的文件)就使用SYSTEM关键字 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
文档声明引用的是文档标识符时(由公共组织定义的公认的标识符,如W3C定义的),就使用PUBLIC关键字。 

这边还在文档标识符后加了url标识的dtd文件,就是在文档标识符无法识别时备用的。 

processing instruction  
<?xml-stylesheet href="XSL/yuan.html.xsl" type="text/xsl"?> 
xml样式表指令。这里不做具体的介绍,只是知道下processing instruction在xml中是这么个东西。看api时也好理解一些。 

xml元素(就是经常看到的标签)。  
如在html中经常看到的就是: 
<div></div> // 仅有名称的标签 
<img /> // 自关闭标签 
<a href=""></a> // 带有属性的标签 

文本内容  
就是在根标签内间的文本内容。(xml规范规定xml的内容必须在根标签内) 
如: 
<root> 
text1 
    <tag1>text2</tag1> 
    <tag2> 
        <tag3>text3</tag3> 
    </tag2> 
</root> 

entity reference实体引用  
在配置java环境变量时,就有一个类似的实体引用。比如我们会配置:JAVA_HOME:c:\java\jdk1.6.20,然后在path变量中加入:%JAVA_HOME%\bin;。这就是一个实体引用,就是把JAVA_HOME处的值替换过来。 

xml中的实体引用的语法是:&[实体名];(windows的环境变量中的语法是%[实体名]%)。xml中也预定义了几个可被引用的实体名:就是lt(<), gt(>), amp(&), quot("), apos(')。 

CDATA section  
xml规范中规定,这部分的内容不需要(解析器)做任何的处理,就按它原来的内容显示。只要将这部分的内容需要放入<![CDATA[     内容处    ]]>中就可以了。 
<![CDATA[ <div></div> &lt; &gt; &amp; ]]> 里面的内容不会被进行任何的处理。 

注释  
xml中使用<!-- -->来注释内容。 
如:<!-- 这里面的内容都是注释 --> 


xml中的相关术语:  
dtd、schema:  
两种文档约束语言,是用来写xml文档规则的。就是通过它们可以规定一个xml中可以使用哪些标签,哪些标签分别有哪些属性,哪个标签可以出现在哪个标签内部等一系列的规则。 

well-formed: 遵守xml规范的xml文档就是well-formed的。 
valid: 遵守dtd、schema约束的就是valid的。 

命名空间:  
命名空间的作用是用来区别有着相同名字,但却具有不同功能的东西。和编程语言的命名空间应该是差不多的功能。比如:同样的叫XmlParser,可能一个是来自java标准库的javax.xml.XmlParser(仅仅是举例);另一个是来自apache的(org.apache.XmlParser)。 
xml规范规定,需要使用一个唯一的URI和其缩写来指定命名空间。同时,每个xml文档都具有一个默认的命名空间(即不指定时) 

// 默认命名空间的一个元素 
<yuanzhifei89 
    xmlns:java="http://yuanzhifei89.iteye.com/javax/xml" 
    xmlns:apache="http://yuanzhifei89.iteye.com/org/apache"> 
        // java命名空间的解析器去解析该xml 
        <apache:XmlParser>d:\file.xml</apache:XmlParser> 

        // apache命名空间的解析器去解析该xml 
        <java:XmlParser>d:\file.xml</java:XmlParser> 
</yuanzhifei89> 

推式解析器和拉式解析器  
推式解析器是一种主动类型的解析器,它在解析xml的过程中,会将解析到的东西主动的推送给我们。比如,在解析到<div>这种时,它就会发给我们一个startTag的事件;同时整个解析过程都是全自动的(即必须从xml开始到xml结束)。 

拉式解析器与其相对,是一种被动的解析器,我们想要什么东西得向它去请求才行。比如,我们想要<div>这种时,必须不断的去next()来找到该事件;同时它的整个解析过程是被动的,我们想解析到哪就解析到哪。 



专为JavaME等移动设备设计的解析api  
该部分api主要在org.xmlpull.v1包下,主要有以下几个类或接口: 
XmlPullParser:该接口定义了XMLPULL V1 API中需要的解析功能。 
XmlSerializer:该接口定义了序列化xml的需要的方法。 

XmlPullParserFactory:Xml解析器工厂类。一般都是用该工厂来创建解析器实例,这样在需要时切换为想要的解析器实现类。 
XmlPullParserException:不需多解释,异常最好理解。在解析过程中遇到非正常情况就会抛出该异常。 

使用XmlPullParser解析xml  
XmlPullParser是一种拉式解析器,所有的事件必须我们自己去请求。 

当我们不断的请求XmlPullParser事件时,会获取到的事件类型  
DOCDECL 
读到document type declaration时(就是<DOCTYPE),就报告该事件。 

PROCESSING_INSTRUCTION 
处理指令。看上面的xml组成中有介绍什么是处理指令。 

CDSECT 
读到CDATA Section就报告该事件 

COMMENT 
读到注释时就报告该事件 

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

START_DOCUMENT 
xml刚开始时,报告该事件 

END_DOCUMENT 
xml结束时,就报告该事件 

START_TAG 
读到开始标签时,就报告该事件。如:读到<div>这种时 

END_TAG 
读到结束标签时,就报告该事件。如:读到</div>这种时 

TEXT 
读到内容时,就报告该事件。如:读到<div>内容</div>,标签间的内容时 

xml的解析过程就是不断的请求事件,然后根据相应的事件做相应的处理  
XmlPullParser中提供的获取事件的方法: 
next(); 
主要是用于返回比较高层的事件的。其中包括:START_TAG, TEXT, END_TAG, END_DOCUMENT 

nextToken(); 
能够返回所有的事件。 

对于一般的解析,只需要用到XmlPullParser的几个获取值的api就够了: 
getName(); 
该api只有在当前的事件为START_TAG(返回标签名),END_TAG(返回标签名)和ENTITY_REF(返回实体引用名)。其它的事件都返回null。 

getText(); 
该api只有在当前的事件为TEXT(返回文本内容),ENTITY_REF(返回实体引用引用的内容),CDSECT(返回其内部的内容),COMMENT(返回注释内容)。其它的事件一般都返回null。 

nextText(); 
该api的正常执行是由条件的:要当前的事件为START_TAG,接下来两个事件为(TEXT), END_TAG。如果不满足就会抛异常(即:TEXT后再出现TEXT也是不行的)。如果当前事件为START_TAG,下一个为TEXT,则返回文本内容;如果下一个是END_TAG,则返回"",同时将事件置为END_TAG。 

一般用途的解析  
一般像微博这种,用xml作为数据交换时。返回的xml格式是很紧凑的(便于解析): 
<root><data><create>8</create><fans>4</fans><home>9</home><mentions>0</mentions><private>0</private></data><errcode>0</errcode><msg>ok</msg><ret>0</ret></root> 
Xml代码   收藏代码
  1. <!-- 便于阅读的格式 -->  
  2. <root>  
  3.     <data>  
  4.         <create>8</create>  
  5.         <fans>4</fans>  
  6.         <home>9</home>  
  7.         <mentions>0</mentions>  
  8.         <private>0</private>  
  9.     </data>  
  10.     <errcode>0</errcode>  
  11.     <msg>ok</msg>  
  12.     <ret>0</ret>  
  13. </root>  

Java代码   收藏代码
  1. XmlPullParserFactory parserFactory = XmlPullParserFactory.newInstance();  
  2. XmlPullParser parser = parserFactory.newPullParser();  
  3. // 因为xml仅仅是数据,没有xml声明,doctype这种,所以不需要做任何设置,直接解析即可  
  4. FileReader reader = new FileReader(xmlFile);  
  5. parser.setInput(reader);  
  6.   
  7. // 该解析器是拉式解析器,所以只有靠我们自己去获取事件  
  8. // 当遇到END_DOCUMENT事件时,就可以结束事件的获取了,所以:  
  9. int eventType = 0;  
  10. String tagName = null;  
  11. while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {  
  12.     if (eventType == XmlPullParser.START_TAG) {  
  13.         tagName = parser.getName();  
  14.           
  15.         // 正常情况下,已知的标签是START_TAG + TEXT + END_TAG的。  
  16.         // 意外情况(比如服务器返回的xml不完整),此时就应该抛异常,所以这里就按照正常的逻辑写代码好了  
  17.         if ("create".equals(tagName)) {  
  18.             // setCreateNum(parser.nextText());  
  19.         } else if ("fans".equals(tagName)) {  
  20.             // setFansNum(parser.nextText());  
  21.         } else if ("home".equals(tagName)) {  
  22.             // setHomeNum(parser.nextText());  
  23.         } else if ("mentions".equals(tagName)) {  
  24.             // setMentions(parser.nextText());  
  25.         } else if ("private".equals(tagName)) {  
  26.             // setPrivateNum(parser.nextText());  
  27.         } else {  
  28.             // unknown or new tag, just pass it  
  29.         }  
  30.     }  
  31. }  


XmlPullParser其它api的使用  
// property, feature相关方法 
setFeature(String featureName, boolean state); 
setProperty(String propertName, Object value); 
getFeature(String featureName); 
getProperty(String propertyName); 

// xml读取方法 
setInput(Reader in); 
setInput(InputStream inputStream, String inputEncoding); 

// 事件请求方法 
next(); 
nextToken(); 
nextTag(); 
nextText(); 

// 其它相关方法 
require(int eventType, String namespace, String name); 
确定eventType是否和getEventType()相同,namespace是否和getNamespace()相同,name是否和getName()相同,有一个不同就抛异常。后两个可以为null(即忽略)。 

getInputEncoding(); 
获取输入xml的encoding。如果能确定则返回编码,否则返回null。 

// 事件类型都已int返回,要知道以文本方式显示的话可以这样 
int eventType = parser.getEventType(); 
String evtTypeText = XmlPullParser.TYPES[eventType]; 

// 其它方法见示例: 
要读取的xml文件: 
Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <persons  
  3.     xmlns:yd="http://www.china-mobile.com"  
  4.     xmlns:lt="http://www.china-unicome.com">  
  5.     some_content  
  6.     <person index="1">  
  7.         <name>yuanzhifei89</name><age>100</age><married>false</married>  
  8.         <!-- 移动号码 --><yd:phone yd:id="amj08102">12345678</yd:phone>  
  9.         <!-- 联通号码 --><lt:phone lt:id="cmk35203">87654321</lt:phone>  
  10.           
  11.         <![CDATA[&lt;&gt; <div>]]>&lt;  
  12.     </person>  
  13. </persons>  

解析代码:从文档开始,一个事件一个事件解析到文档结束,基本涉及了所有api了。 
因为有些api只有在特定的事件上才有返回值,所以有些调用只在部分标签处使用。 
Java代码   收藏代码
  1. // 创建xml解析器  
  2. XmlPullParser parser = mFactory.newPullParser();  
  3. parser.setInput(new FileReader(xmlFile));  
  4.   
  5. // 因为使用的xml涉及了命名空间,所以启用命名空间  
  6. parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);  
  7.   
  8. int eventType = 0;  
  9.   
  10. // xml和person间的IGNOREABLE_WHITESPACE  
  11. eventType = parser.nextToken();  
  12. parser.isWhitespace(); // IGNOREABLE_WHITESPACE总是为whitespace  
  13.   
  14. // 返回这两个前缀对应的命名空间uri,但此时还未解析到命名空间部分,所以均返回null  
  15. parser.getNamespace("lt");  
  16. parser.getNamespace("yd");  
  17.   
  18. // 起始标签<persons>  
  19. eventType = parser.nextToken();  
  20. parser.getAttributeCount(); // 0,persones标签没有属性  
  21.   
  22. // 命名空间已解析  
  23. parser.getNamespace("lt"); // http://www.china-unicome.com  
  24. parser.getNamespace("yd"); // http://www.china-mobile.comp  
  25.   
  26. // <persons>和<person>间的text(空白也算在text内容中)  
  27. eventType = parser.nextToken();  
  28. parser.isWhitespace(); // false,只要含有非空白字符就不是whitespace  
  29.   
  30. // 起始标签<person>  
  31. eventType = parser.nextToken();  
  32.   
  33. // <person>和<name>间的text  
  34. eventType = parser.nextToken();  
  35. parser.isWhitespace(); // true  
  36.   
  37. // 起始标签<name>  
  38. eventType = parser.nextToken();  
  39. parser.getLineNumber(); // 第7行  
  40. parser.getColumnNumber(); // 第9列  
  41.   
  42. // name标签中的text:yuanzhifei89  
  43. eventType = parser.nextToken();  
  44.   
  45. // 结束标签</name>  
  46. eventType = parser.nextToken();  
  47.   
  48. // 起始标签<age>  
  49. eventType = parser.nextToken();  
  50. parser.getNamespace(); // "",age没有命名空间  
  51. parser.isEmptyElementTag(); // false,age并不是<age/>这种空标签  
  52. parser.getDepth(); // 3,<persons>一层,<person>二层,到它就是三层  
  53. parser.getNamespaceCount(parser.getDepth()); // 2,到三层为止解析到了2个命名空间  
  54. // age标签中的text:100  
  55. eventType = parser.nextToken();  
  56. // 结束标签</age>  
  57. eventType = parser.nextToken();  
  58.   
  59. // 开始标签<married>  
  60. eventType = parser.nextToken();  
  61. // 标签married间的text:false  
  62. eventType = parser.nextToken();  
  63. // 结束标签</married>  
  64. eventType = parser.nextToken();  
  65.   
  66. // </married>和<!-- 之间的text  
  67. eventType = parser.nextToken();  
  68.   
  69. // COMMENT备注内容  
  70. eventType = parser.nextToken();  
  71.   
  72. // 开始标签<yd:phone>  
  73. eventType = parser.nextToken();  
  74. parser.getAttributeCount(); // 1,它有一个属性  
  75. parser.getNamespace(); // http://www.china-mobile.com,它是该命名空间下的元素  
  76. parser.getPrefix(); // yd,命名空间前缀是yd  
  77. parser.getAttributeName(0); // id,第1个属性的名称  
  78. parser.getAttributeNamespace(0); // http://www.china-mobile.com,属性也在该命名空间下  
  79. parser.getAttributePrefix(0); // yd,所以前缀也一样  
  80. parser.getAttributeValue(0); // amj08102,属性值  
  81. parser.getDepth(); // 3,和<age>一样,<persons>一层,<person>二层,到它是三层  
  82. parser.getNamespaceCount(parser.getDepth()); // 2,到三层为止解析到了2个命名空间  
  83. // 标签<yd:phone>间的text:12345678  
  84. eventType = parser.nextToken();  
  85. // 结束标签</yd:phone>  
  86. eventType = parser.nextToken();  
  87.   
  88. // </yd:phone>和<!--间的text  
  89. eventType = parser.nextToken();  
  90. parser.getName(); // phone,启用命名空间时返回phone;如果不启用会返回yd:phone  
  91.   
  92. // COMMENT 备注内容  
  93. eventType = parser.nextToken();  
  94. parser.getText(); // 备注内容  
  95.   
  96. // 开始标签<lt:phone>  
  97. eventType = parser.nextToken();  
  98. // 标签<lt:phone>间的内容  
  99. eventType = parser.nextToken();  
  100. // 结束标签</lt:phone>  
  101. eventType = parser.nextToken();  
  102.   
  103. // </lt:phone>和<![CDATA[[]]>间的text  
  104. eventType = parser.nextToken();  
  105.   
  106. // CDSECT:CDATA内容  
  107. eventType = parser.nextToken();  
  108. parser.getName(); // null  
  109. parser.getText(); // CDATA内容  
  110.   
  111. // 实体引用lt  
  112. eventType = parser.nextToken();  
  113. parser.getName(); // 实体引用名lt  
  114. parser.getText(); // 所引用的内容<  
  115.   
  116. // 实体引用lt和</person>间的text  
  117. eventType = parser.nextToken();  
  118.   
  119. // 结束标签</person>  
  120. eventType = parser.nextToken();  
  121.   
  122. // </person>和</persons>间的text  
  123. eventType = parser.nextToken();  
  124.   
  125. // 结束标签</persons>  
  126. eventType = parser.nextToken();  
  127.   
  128. // 文档结束  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值