我有UTF-8 - 但仍然得到“1字节UTF-8序列的无效字节1”

时间:2011-12-12 08:52:04

标签: java xml encoding utf-8 xerces

我即时创建XML字符串(不读取文件)。然后我使用Cocoon 3通过FOP将其转换为PDF。在中间某处的Xerces运行。当我使用硬编码的东西时,一切正常。一旦我将德语变音符号放入数据库并使用该数据丰富我的xml,我得到:

Caused by: org.apache.cocoon.pipeline.ProcessingException: Can't parse the XML string.
at org.apache.cocoon.sax.component.XMLGenerator$StringGenerator.execute(XMLGenerator.java:326)
at org.apache.cocoon.sax.component.XMLGenerator.execute(XMLGenerator.java:104)
at org.apache.cocoon.pipeline.AbstractPipeline.invokeStarter(AbstractPipeline.java:146)
at org.apache.cocoon.pipeline.AbstractPipeline.execute(AbstractPipeline.java:76)
at de.grobmeier.tab.webapp.modules.documents.InvoicePipeline.generateInvoice(InvoicePipeline.java:74)
... 87 more

Caused by: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence.
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:684)
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:554)

然后我调试了我的应用程序并发现,我的“Ä”(数据库来自数据库)的字节值为196,即十六进制的C4。这就是我所期望的:http://www.utf8-zeichentabelle.de/

我不知道为什么我的代码失败了。

然后我尝试手动添加BOM,如:

byte[] bom = new byte[3];
bom[0] = (byte) 0xEF;
bom[1] = (byte) 0xBB;
bom[2] = (byte) 0xBF;
String myString = new String(bom) + inputString;

我知道这不是很好,但我尝试过 - 当然失败了。我试图在前面添加一个xml标题:

<?xml version="1.0" encoding="UTF-8"?>

哪个也失败了。然后我把它结合起来。失败。

毕竟我尝试过类似的东西:

xmlInput = new String(xmlInput.getBytes("UTF8"), "UTF8");

实际上什么都没做,因为它已经是UTF-8了。它仍然失败。

那么......任何想法我做错了什么以及Xerces对我的期待是什么?

由于 基督教

3 个答案:

答案 0 :(得分:13)

如果您的数据库只包含一个字节(值为0xC4),那么您不使用UTF-8编码。

字符“LATIN CAPITAL LETTER A WITH DIAERESIS”具有代码点值U + 00C4,但UTF-8不能在单个字节中对其进行编码。如果你在UTF8-zeichentabelle.de上查看第三列“UTF-8(十六进制)”,你会看到UTF-8将其编码为0xC3 84(两个字节)。

请阅读Joel的文章“The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)”以获取更多信息。


编辑:克里斯蒂安自己找到了答案;原来这是Cocoon 3 SAX组件中的一个问题(我猜它是alpha 3版本)。事实证明,如果您将XML作为String传递到XMLGenerator类,那么在SAX解析期间会出现问题导致此混乱。

looked up the code找到Cocoon-stax中的实际问题:

if (XMLGenerator.this.logger.isDebugEnabled()) {
    XMLGenerator.this.logger.debug("Using a string to produce SAX events.");
}
XMLUtils.toSax(new ByteArrayInputStream(this.xmlString.getBytes()), XMLGenerator.this.getSAXConsumer();

如您所见,调用getBytes()将创建一个带有JRE默认编码的Byte数组,然后无法解析。这是因为XML声明自己是UTF-8,而数据现在再次以字节为单位,并且可能使用Windows代码页。

作为一种解决方法,可以使用以下内容:

new org.apache.cocoon.sax.component.XMLGenerator(xmlInput.getBytes("UTF-8"),
       "UTF-8");

这将触发正确的内部动作(正如Christian通过试验API发现的那样)。

我在Apache的bug追踪器中opened an issue

编辑2:问题已修复,将包含在即将发布的版本中。

答案 1 :(得分:2)

您在该页面上看到的C4是指unicode代码点U+00C4。用于表示UTF-8中的这种代码点的字节序列不是"\xC4"。你想要的是UTF-8(十六进制)列中的内容,即"\xC3\x84"

因此,您的数据不是UTF-8。

您可以阅读有关如何使用UTF-8 here编码数据的方法。

答案 2 :(得分:0)

我正在使用TextPad作为文本编辑器运行Windows 7,以手动构建xml数据文件。我得到了MalformedByteSequenceException。我在xml文件中的规范是UTF-8。在探索之后,我发现我的编辑器有一个工具“工具...转换为DOS”。我这样做了,重新保存了文件,异常消失了,我的代码运行正常。

然后我在编辑器中查看了该文件类型的默认编码。它是ASCII,但是当我将xml编码参数更改为ASCII时,我得到另一个不同的MalformedByteSequenceException

因此,在Windows系统上,您可以尝试将xml编码保持为UTF-8,但保存编码的DOS文件。我没有进一步深入研究为什么这样做。