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的处理过程是这样的,对文本进行遍历,当发现<、/>、&等这些关键字符时,触发事件,有兴趣可以看看源码;
源代码在:\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));
}
从上面可以看到,处理带有&<>&;这些字符时,分成了几段文本节点。
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解析器的问题的更多相关文章
- android XML解析器全解案例
1.使用pull解析 package com.example.myxml; import java.io.InputStream; import java.util.ArrayList; import ...
- Android xml 解析
XML 经常使用的三种解析方式: DOM: 所有载入到内存,生成一个树状结构,占用内存比較大. SAJ: 採用事件驱动,速度快,效率高,不支持回退. PULL:也是採用事件驱动,语法简洁. 步骤: 1 ...
- Android] Android XML解析学习——方式比较
[Android] Android XML解析学习——方式比较 (ZT) 分类: 嵌入式 (From:http://blog.csdn.net/ichliebephone/article/deta ...
- Duilib源码分析(三)XML解析器—CMarkup
上一节介绍了控件构造器CDialogBuilder,接下来将分析其XML解析器CMarkup: CMarkup:xml解析器,目前内置支持三种编码格式:UTF8.UNICODE.ASNI,默认为UTF ...
- tinyxml一个优秀的C++ XML解析器
读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好. TinyXML是一个开源的解 ...
- TinyXML:一个优秀的C++ XML解析器
//-------------------------------------------------------------------------------------------------- ...
- 转:TinyXM--优秀的C++ XML解析器
读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好. TinyXML是一个开源的解 ...
- android XMl 解析神奇xstream 六: 把集合list 转化为 XML文档
前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...
- android XMl 解析神奇xstream 五: 把复杂对象转换成 xml ,并写入SD卡中的xml文件
前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...
随机推荐
- BZOJ 3907: 网格( 组合数 + 高精度 )
(0,0)->(n,m)方案数为C(n,n+m), 然后减去不合法的方案. 作(n,m)关于y=x+1的对称点(m-1,n+1), 则(0,0)->(m-1,n+1)的任意一条路径都对应( ...
- OpenGL ES 正反面设置指令
在OpenGL ES 中,仅有一种表面网格表示方式,那就是三角形. 三角形的三个顶点,可以组几个面?有答 1 的没有?有!那就是还不懂OpenGL ES 的我. 事实上,一张纸是有正反面的,那么一个三 ...
- 查看Oracle有哪些表或者视图
转自:http://www.2cto.com/database/201211/167577.html 1.查询当前用户下,有哪些表 Sql代码 SELECT * FROM user_tables ...
- 第三章 视图和URL配置
在Mysite文件夹中,创建一个views.py的空文件,输入: from django.http import HttpResponse def hello(request): return Htt ...
- 关于 IE firefox Chrome下的通过用js 关闭窗口的一些问题
首先IE是可以通过window.close()来关闭浏览器窗口的,但是在firefox和Chrome下是无效的,原因在于: ~~~ie可直接<button onclick="windo ...
- js正则:零宽断言
JavaScript正则表达式零宽断言 var str="abnsdfZL1234nvcncZL123456kjlvjkl"var reg=/ZL(\d{4}|\d{6})(?!\ ...
- Spreadsheets
很水的一道题,提醒自己要认真,做的头都快晕了.考虑26的特殊情况. D - Spreadsheets Time Limit:10000MS Memory Limit:65536KB 6 ...
- swift菜鸟入门视频教程-07-闭包
本人自己录制的swift菜鸟入门,欢迎大家拍砖.有什么问题能够在这里留言. 主要内容: 闭包表达式(Closure Expressions) 跟随闭包(Trailing Closures) 值捕获(C ...
- redis缓存工具Jedis进行跨jvm加锁(分布式应用)--不幸暂弃用--能够做第三方锁使用
近期使用redis碰到了多个并发处理同一个缓存的情况.在这样的情况下须要进行加锁机制. 本来想使用java自带的ReadWriteLock进行设置读写锁,这也是上家公司使用的方法. 后来经过商讨,给予 ...
- Javascript 学习 笔记一
1.操作 HTML 元素 如需从 JavaScript 訪问某个 HTML 元素,您能够使用 document.getElementById(id) 方法. 请使用 &qu ...