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

Chr*_*ian 6 java xml encoding utf-8 xerces

我动态创建一个XML String(不读取文件).然后我使用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)
Run Code Online (Sandbox Code Playgroud)

然后我调试了我的应用程序并发现,我的"Ä"(数据库中出现)的字节值为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;
Run Code Online (Sandbox Code Playgroud)

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

<?xml version="1.0" encoding="UTF-8"?>
Run Code Online (Sandbox Code Playgroud)

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

毕竟我尝试过这样的事情:

xmlInput = new String(xmlInput.getBytes("UTF8"), "UTF8");
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢Christian

JBe*_*ert 13

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

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

请阅读Joel的文章" 绝对最低限度,每个软件开发人员绝对必须知道关于Unicode和字符集(没有借口!) "的更多信息.


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

查找代码以找到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();
Run Code Online (Sandbox Code Playgroud)

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

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

new org.apache.cocoon.sax.component.XMLGenerator(xmlInput.getBytes("UTF-8"),
       "UTF-8");
Run Code Online (Sandbox Code Playgroud)

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

我在Apache的bug跟踪器中打开了一个问题.

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