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

一,问题现象

我们解析的代码是:

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>    <result>        <history_info_list>            <row>                <title>程序员 &lt特别版&gt 第1卷</title>                <volume_number>001</volume_number>            </row>        </history_info_list>    </result></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

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&;这些字符时,分成了几段文本节点。

三,解决方案

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

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

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

   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;    } 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(); }

更多相关文章

  1. android TextView多行文本(超过3行)使用ellipsize属性无效问题的
  2. textview中自动换行显示文本内容
  3. TextView——文本省略显示
  4. Android中的文本框,图片以及点击事件的设置
  5. AutoCompleteTextView(自动完成文本框)
  6. android文本内容自动朗读实例教程
  7. Android之UI学习篇一:TextVeiw如何显示丰富的文本
  8. android:layout_marginLeft指该控件距离边父控件的边距, android:

随机推荐

  1. Android(安卓)Intent传递对象
  2. Android(安卓)Google购买PHP服务器端验证
  3. Android之插入通话记录,短信箱插入短信,号
  4. 某android平板项目开发笔记----aChartEng
  5. 如何在Android程序中使用ACRA3(How to ins
  6. Android33_Animations使用(一)
  7. ViewHolder VS HolderView ?
  8. Android获取摄像头视频帧并实时处理(转载
  9. Android(安卓)学习记录—新家
  10. Android数据库中查找一条数据使用的方法