Android XML解析器的问题

来源:互联网 发布:centos ftp配置 编辑:程序博客网 时间:2024/06/09 20:42

最近在项目中遇到了一个解析XML的问题,我们是用android自带的DOM解析器来解析XML的,但发现了一个android的问题,那就是在2.3的SDK上面,无法解析像<, >, 等字符串。

一,问题现象

我们解析的代码是:

[java] view plaincopy
  1. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();   
  2. DocumentBuilder builder = factory.newDocumentBuilder();   
  3. Document documnet = builder.parse(in);  
  4. Element root = documnet.getDocumentElement();  

其中builder.parse(in)中的in是一个InputStream类型的输入流,例如有如下一段XML: 

[javascript] view plaincopy
  1. <?xml version="1.0" ?>  
  2. <data>  
  3.     <result>  
  4.         <history_info_list>  
  5.             <row>  
  6.                 <title>程序员 &lt特别版&gt 第1卷</title>  
  7.                 <volume_number>001</volume_number>  
  8.             </row>  
  9.         </history_info_list>  
  10.     </result>  
  11. </data>  
其中有一个title结点,中间包含< >,但是XML中已经用了转义,所以应该是能正常解析出来的,但在SDK2.3(准确说来应该是3.0以下),它对这些转义字符作了特殊处理,它会把title中间文字当成四个文本结点,其内容分别是:

1, 程序员

2, <

3, 特别版

4, > 第1卷

所以,这是不正确的,其实它应该就是一个节点,内容是[ 程序员<特别版> 第1卷 ]。不过在3.0的SDK,这种问题被修正了。

二,问题原因

好,上面说的是现象,我们现在说一下造成这种现象的原因及解决办法。看android源码发现: android的XML解析实现用的是apache harmony代码,我想android的dalvik应该就是apache的harmonyxml parser,这个没有深究。而实际上harmony的XML解析用的又是KXML,看来android就是一堆开源的代码叠加起来的。下面仔细来看看:XML的处理过程是这样的,对文本进行遍历,当发现<、/>、&等这些关键字符时,触发事件,有兴趣可以看看源码;

源代码在:\libcore\luni\src\main\java\org\apache\harmony\xml\parsers\DocumentBuilderImpl.java

[java] view plaincopy
  1. 113行:XmlPullParser parser = new KXmlParser();  
  2. 265行:else if (token == XmlPullParser.TEXT)  
  3. node.appendChild(document.createTextNode(parser.getText()));  
  4. 277行:else if (token == XmlPullParser.ENTITY_REF)  
  5. String entity = parser.getName(); if (entityResolver != null) {  
  6. // TODO Implement this...  
  7. } String replacement = resolveStandardEntity(entity);  
  8. if (replacement != null) {  
  9. node.appendChild(document.createTextNode(replacement));  
  10. else {  
  11. node.appendChild(document.createEntityReference(entity));  
  12. }  

从上面可以看到,处理带有&<&gt&;这些字符时,分成了几段文本节点。

三,解决方案

问题的原因我们已经知道了,怎么解决呢?

1,判断一下,如果子结点全是文本结点的话,把结点的所有文本字符串拼起来。
2,更改上面的处理方法,node.appendChild这行代码,当发现这个节点的第一个子节点是文本节点时,把当前字符加上去。

在项目中所采用的方法是第一种,因为这方法简单,实现如下: 

[java] view plaincopy
  1.    public static boolean areAllSubNodesTextType(Node node)  
  2.    {  
  3.         if (null != node)  
  4.         {  
  5.             int nodeCount = node.getChildNodes().getLength();  
  6.             NodeList list = node.getChildNodes();  
  7.             for (int i = 0; i < nodeCount; ++i)  
  8.             {  
  9.                 short noteType = list.item(i).getNodeType();  
  10.                 if (Node.TEXT_NODE != noteType)  
  11.                 {  
  12.                     return false;  
  13.                 }  
  14.             }  
  15.         }  
  16.   
  17.         return true;  
  18.     }  
  19.   
  20.     private static String getNodeValue(Node node)  
  21.     {  
  22.         if (null == node)  
  23.         {  
  24.             return "";  
  25.         }  
  26.   
  27.         StringBuffer sb = new StringBuffer();  
  28.   
  29.         int nodeCount = node.getChildNodes().getLength();  
  30.         NodeList list = node.getChildNodes();  
  31.         for (int i = 0; i < nodeCount; ++i)  
  32.         {  
  33.             short noteType = list.item(i).getNodeType();  
  34.             if (Node.TEXT_NODE == noteType)  
  35.             {  
  36.                 sb.append(list.item(i).getNodeValue());  
  37.             }  
  38.         }  
  39.      }  
  40.   
  41.         return sb.toString();  
  42.     }  

原文连接:http://blog.csdn.net/leehong2005/article/details/7299352
感谢原作者!