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

尽管我们从服务器端返回的数据中,应该是不能包含< >这样的字符,应该使用转义,但有时候,由于历史原因,导致服务器端不能作这样的修正,所以这样的问只能是在客户端来解决了。下面我就说一说我们是如何解决这种问的。

1,现象

我们的解析代码是:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
DocumentBuilder builder = factory.newDocumentBuilder(); 
Document documnet = builder.parse(in);
Element root = documnet.getDocumentElement();

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

<?xml version="1.0" ?>
<data>
<success>1</success>
<error>
<code></code>
<message></message>
</error>
<result>
<history_info_list>
<row>
<purchase_info_id>dnrxmauxecj3z6e4</purchase_info_id>
<title_id>134051</title_id>
<title>まもって守護月天!再逢<Retrouvailles></title>
<volume_number>001</volume_number>
<author_name>桜野みねね</author_name>
<contents_name>まもって守護月天!再逢<Retrouvailles> 1巻</contents_name>
<date_open>2011-12-02</date_open>
<purchase_date>2012-02-06 18:39:48</purchase_date>
<image_url>/resources/c_media/images/thumb/262/134051_01_1_L.jpg</image_url>
<contents>
<story_number>1</story_number>
<contents_id>BT000013405100100101500014</contents_id>
<file_size>34168162</file_size>
<Within_Wifi>0</Within_Wifi>
</contents>
<text_to_speech_flg>0</text_to_speech_flg>
<restrict_num>-1</restrict_num>
<issue>3</issue>
<subscription>0</subscription>
<adult_flg>0</adult_flg>
</row>
</history_info_list>
</result>
</data>

其中有一个title结点,中间包含< >,但是XML中已经用了转义,所以应该是能正常解析出来的,但在SDK2.3(准确说来应该是3.0以下),它对这些转义字符作了特殊处理,它会把title中间文字当成四个文本结点,其内容分别是:

1, まもって守護月天!再逢

2, <

3, Retrouvailles

4, > 1巻

所以,这是不正确的,其实它应该就是一个节点,内容是[ まもって守護月天!再逢<Retrouvailles> 1巻 ]。不过在3.0的SDK,这种问题被修正了。

2,问题的原因

好,上面说的是现象,我们现在说一下造成这种现象的原因及解决办法。

翻看android源码发现:

android的XML解析实现用的是apache harmony代码,我想android的dalvik应该就是apache的harmonyxml parser,这个没有深究。

而实际上harmony的XML解析用的又是KXML,看来android就是一堆开源的代码叠加起来的。

下面仔细来看看:KXML的处理过程是这样的,对文本进行遍历,当发现<、/>、&等这些关键字符时,触发事件,有兴趣可以看看源码;

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

113行: XmlPullParser parser = new KXmlParser();
265行:else if (token == XmlPullParser.TEXT)
node.appendChild(document.createTextNode(parser.getText()));
277行:else if (token == XmlPullParser.ENTITY_REF)
String entity = parser.getName(); if (entityResolver != null) {
// TODO Implement this...
} String replacement = resolveStandardEntity(entity);
if (replacement != null) {
node.appendChild(document.createTextNode(replacement));
} else {
node.appendChild(document.createEntityReference(entity));
}

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

3,解决方案

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

1,判断一下,如果子结点全是文本结点的话,把结点的所有文本字符串拼起来。

2,更改上面的处理方法,node.appendChild这行代码,当发现这个节点的第一个子节点是文本节点时,把当前字符加上去。

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

/**
* This method is used to indicate the specified node's all sub nodes are text node or not.
*
* @param node The specified node.
*
* @return true if all sub nodes are text type, otherwise false.
*/
public static boolean areAllSubNodesTextType(Node node)
{
if (null != node)
{
int nodeCount = node.getChildNodes().getLength();
NodeList list = node.getChildNodes();
for (int i = 0; i < nodeCount; ++i)
{
short noteType = list.item(i).getNodeType();
if (Node.TEXT_NODE != noteType)
{
return false;
}
}
} return true;
} /**
* Get the node value. If the node's all sub nodes are text type, it will append
* all sub node's text as a whole text and return it.
*
* @param node The specified node.
*
* @return The value.
*/
private static String getNodeValue(Node node)
{
if (null == node)
{
return "";
} StringBuffer sb = new StringBuffer(); int nodeCount = node.getChildNodes().getLength();
NodeList list = node.getChildNodes();
for (int i = 0; i < nodeCount; ++i)
{
short noteType = list.item(i).getNodeType();
if (Node.TEXT_NODE == noteType)
{
sb.append(list.item(i).getNodeValue());
}
} return sb.toString();
}
}







Android XML解析器的问题的更多相关文章

  1. android XML解析器全解案例

    1.使用pull解析 package com.example.myxml; import java.io.InputStream; import java.util.ArrayList; import ...

  2. Android xml 解析

    XML 经常使用的三种解析方式: DOM: 所有载入到内存,生成一个树状结构,占用内存比較大. SAJ: 採用事件驱动,速度快,效率高,不支持回退. PULL:也是採用事件驱动,语法简洁. 步骤: 1 ...

  3. Android] Android XML解析学习——方式比较

     [Android] Android XML解析学习——方式比较 (ZT)  分类: 嵌入式 (From:http://blog.csdn.net/ichliebephone/article/deta ...

  4. Duilib源码分析(三)XML解析器—CMarkup

    上一节介绍了控件构造器CDialogBuilder,接下来将分析其XML解析器CMarkup: CMarkup:xml解析器,目前内置支持三种编码格式:UTF8.UNICODE.ASNI,默认为UTF ...

  5. tinyxml一个优秀的C++ XML解析器

    读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好. TinyXML是一个开源的解 ...

  6. TinyXML:一个优秀的C++ XML解析器

    //-------------------------------------------------------------------------------------------------- ...

  7. 转:TinyXM--优秀的C++ XML解析器

    读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好. TinyXML是一个开源的解 ...

  8. android XMl 解析神奇xstream 六: 把集合list 转化为 XML文档

    前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...

  9. android XMl 解析神奇xstream 五: 把复杂对象转换成 xml ,并写入SD卡中的xml文件

    前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...

随机推荐

  1. 【转载】国内网站博客数据统计选免费Google Analytics还是百度统计

    [转载]国内网站博客数据统计选免费Google Analytics还是百度统计 Google Analytics谷歌统计是我用的第一个网站统计工具,当然现在也一直在用.Google Analytics ...

  2. PHP数组与对象之间用递归转换

    2 3 4 5 6 7 8  function object_to_array($e) {      $_arr = is_object($e) ? get_object_vars($e) : $e; ...

  3. projecteuler之58题Spiral primes

    package com.android; public class SpiralPrimes { public static void main(String args[]) { long numPr ...

  4. 用JS判断用户使用的是手机端还是pc端访问

    最近项目中用到一个应用,当访问同一个网站地址的时候,例如:www.xxx.com的时候,如果当前客户端是pc则跳转到专注于pc的部分,如果当前客户机是手机,则跳转到专注于手机的部分,秉承一贯的习惯,b ...

  5. 第三节 ISBN 码 / ISSN 码

    ISBN与ISSNEAN的用途很广,除了我国的商品条码CAN以及日本商品条码JAN外,目前国际认可的书籍代号与期刊号的条码,也都是由EAN变身而来的.书籍的国际认可代号称为国际标准书号(Interna ...

  6. hibernate Annotation 以及注解版的数据关联 4.4

    目的是不写xxx.hbm.xml映射文件,使用注解 主配置文件还是要有hibernate.cfg.xml <?xml version="1.0" encoding=" ...

  7. 基于visual Studio2013解决C语言竞赛题之0408素数

      题目 解决代码及点评 判断一个数是不是素数的方法,一般是看n是不是能被n以内的某个整数(1除外)整除 为了提高效率,这个整数范围一般缩小到n的平方根 如果在这个范围内的整数都不能整除,那么 ...

  8. Linux 各类软件整理汇总

    关于前端和后端的解释 详细链接见:http://wiki.ubuntu.org.cn/Qref/Apps Linux下程序通常不需要作为一个整体,而是模块化,于是有了可选的前端和后端——这种情况下:前 ...

  9. CSS的三种样式:内联式,嵌入式,外部式以及他们的优先级

    从CSS 样式代码插入的形式来看基本能够分为下面3种:内联式.嵌入式和外部式三种. 1:内联式css样式表就是把css代码直接写在现有的HTML标签中,如以下代码: <p style=" ...

  10. ajaxfileupload.js 文件上传

    一,前台代码. <input id="fileToUpload" type="file" size="25" name="f ...