由于sax是触发式的解析xml流, 在手持设备的系统中,应用相当广泛. 在android的应用开发中,自然也偏向于选择sax来解析xml了.
在做一份rss应用中,需要解析baidu.com的rss文件时遇到了not well-formed的错误. 查询了相关资料以及不断debug and log之后, 终于确定了是文件编码遇到了问题.
在国内,资讯内容提供商使用的rss编码各不相同 网易使用gb2312, 新浪utf-8, 百度GBK 等等.
1. 当URL请求rss.xml后, 通过openStream将返回一个InputStream的字节流对象, 字节流本身是不带编码信息的.
2. 得到字节流后,通常是可以直接使用InputStream对象去生成一个InputSource对象,来给saxParser或者是XmlReader进行解析的. 默认的情况下, parser解析的InputSource对象是按照utf8编码方式的, 所以,在不做任何处理时, utf8编码的xml文件解析是正常的.
3. 当遇到Gbk,或者gb2312编码时,解析ANSI字符是没有问题的,解析到中文时,parser是按照默认的UTF8编码进行解析的, UTF8是每个字符分配3字节, gb2312是分配两字节,必然会造成错误.这时也就报出了not well-formed error.
当时注意到inputSource有个setEncoding的方法,是告诉sarpar使用何种编码去解析这个inputStream, 你可以设置使用GBK去解析这个stream, 但是资源文件的编码都是utf8,而你使用GBK去解析明显是不符合的.
4. SetEncoding是不会将编码进行转换的,仅仅是告诉sarpar如何去解析, 那么遇到xml encoding是gbk gb2312的情况下, 可以使用inputStreamReader的方式, inputStreamReader(inputStream, charsetName)来指定编码生成字符流.这里显然发生了编码转换.
然后传递这个字符流对象到InputSource对象,这个对象在接受字符流时,是不能setEncoding的, 原因也很简单,字符流是带编码信息的,仍然不放心可以再次setEncoding(不过是无效的)。
5. 这样最后只要通过判别文件的编码方式,然后告诉sarpar如何去解析,程序就可以正常执行了.
识别字节流的编码方式可以google查询到很多方法,常用的是通过mozilla提供的一个开源工具来识别的. 目前最新为: cpdetector_1.0.8 可以在SourceForge下载到.
关键代码: