zoukankan      html  css  js  c++  java
  • Android XML解析器的问题

    最近在项目中遇到了一个解析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的处理过程是这样的,对文本进行遍历,当发现<、/>、&等这些关键字符时,触发事件,有兴趣可以看看源码;

    源代码在:libcorelunisrcmainjavaorgapacheharmonyxmlparsersDocumentBuilderImpl.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();
        }
    }









  • 相关阅读:
    day-11函数的形参与实参
    day-10初级函数
    .检查用户名是否使用接口
    04.vue发送短信逻辑
    03.celery发送短信接口
    02.celery配置与基本使用
    Celery介绍
    python爬虫与Django框架vue交互的前后端代码详情(励志人生网实例)
    爬虫找工作之面试题(2)
    爬虫找工作之面试题(1)
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3144774.html
Copyright © 2011-2022 走看看