0

我正在将一个为 BlackBerry (Java) 编写的项目移植到 Android。该项目包含一些针对org.xmlpull.v1.XmlPullParser接口编写的 xml 解析类。实际的解析器实例从外部注入到这些类中。

此应用程序解析以ISO-8859-15(又名拉丁 9)编码的 xml 文件。我不能使用 UTF-8,不幸的是我需要坚持这种编码。

旧的 BlackBerry 项目使用kxml2拉解析器。现在在android中我试图使用可以像这样获得的内置解析器:

XmlPullParser parser = Xml.newPullParser();

然后我配置字符编码:

parser.setInput(<input stream>, "ISO-8859-15");

问题是这个解析器不支持这种字符编码。这是抛出的异常:

org.xmlpull.v1.XmlPullParserException: Error parsing document. (position:line -1, column -1) caused by: org.apache.harmony.xml.ExpatParser$ParseException: At line 1, column 0: unknown encoding.

这真的很奇怪,因为我知道 Android 支持这种编码。证明是这条线毫无例外地运行:

String test  = new String("hi".getBytes(), "ISO-8859-15");

但是,如果我为解析器配置不同的编码,如 UTF-8 或 latin-1,它就可以工作。

接下来我尝试在 Android 中使用旧项目的解析器(kxml2),但后来出现了新错误:

org.xmlpull.v1.XmlPullParserException: unexpected type (position:END_DOCUMENT null@9:1 in java.io.InputStreamReader@43e97088)

即使我可以毫无问题地使用它,kxml2 在过去几年(最后一个版本于 2006 年发布)都没有得到支持,所以如果可能的话,我想使用 Android 的 pull 解析器,它更健壮,性能也更好.

我可以欺骗默认的解析器调用parser.setInput(bais, "ISO-8859-1");,因为这样它会忽略文件中 XML 声明中的编码,并且它之所以有效,是因为两个字符集具有相同数量的字符并且它们中的大多数是相同的。但是这样一来,查看源代码的人可能会认为它使用 latin-1,而实际上它接收到 latin-9 中的输入并因此生成 latin-9 中的字符串。

默认 XML Pull Parser 是否有任何理由不支持 ISO-8859-15?是否有任何具有良好字符编码支持的替代 PULL 解析库?

提前致谢。


更新:当我写这个问题时,我已经测试了 OS 2.2 和 2.3 中的默认解析器。但是,阅读 javadocXml.newPullParser我发现了这一点:

注意:这实际上比 SAX 解析器慢,而且还没有完全实现。如果您需要一个快速的、主要实现的拉解析器,请使用它。如果您需要完整的实现,请使用 KXML。

事实上,在测试 OS 4.x 中的默认解析器时,我遇到了第二个异常。看起来对于 OS 4,内置解析器实际上是 kxml!

4

1 回答 1

0

好吧,看起来很难找到一个好的 XmlPullParser 库,所以我将按照 javadocs 中关于Xml.newPullParser工厂方法的建议使用 kxml 的解析器。(我没有在在线 javadocs 中找到此注释,仅在 eclipse 的 javadoc 窗口中找到。也许我使用的是旧的 javadocs,后来在 Android 开始使用 kxml 作为内置解析器后删除了此注释)。

至于使用kxml的解析器时抛出的异常,是这样的:

org.xmlpull.v1.XmlPullParserException: unexpected type (position:END_DOCUMENT null@9:1 in java.io.InputStreamReader@43e97088)

原来这是由我的代码引起的。在最初的移植中,我意识到 Froyo 和 Gingerbread 中包含的 Android 内置解析器在调用parser.nextText. 所以我parser.nexTag在这里和那里添加了一些行来使它工作。然后我再次切换到 kXml,但我保留了那些额外的行,这使得我的 KXmlParser 实例在处理文件末尾时搞砸了。nextTag到达文件末尾后调用时会引发异常。这也在以下文档中进行了解释nextTag

如果是 START_TAG 或 END_TAG 则调用 next() 并返回事件,否则抛出异常

于 2013-05-10T08:45:06.040 回答