Android XML解析器的問題

來源:互聯網
上載者:User

最近在項目中遇到了一個解析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();    }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.