JAXB错误解释:无效的1字节UTF-8序列的第1个字节

5
我们正在使用JAXB解析XML文档,但出现了以下错误:
[org.xml.sax.SAXParseException: Invalid byte 1 of 1-byte UTF-8 sequence.]
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:315)

这到底是什么意思,我们该如何解决??
我们正在执行以下代码:
jaxbContext = JAXBContext.newInstance(Results.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema(getSchema());
results = (Results) unmarshaller.unmarshal(new FileInputStream(inputFile));

更新

问题似乎是由XML文件中的这个“有趣”的字符引起的:¿

为什么会导致这样的问题呢?

更新2

文件中有两个奇怪的字符。它们在文件的中间左右。请注意,该文件是基于数据库中的数据创建的,这些奇怪的字符不知何故进入了数据库。

更新3

以下是完整的XML片段:

<Description><![CDATA[Mt. Belvieu ¿ Texas]]></Description>

更新4

请注意,没有<?xml ...?> 头。

特殊字符的十六进制为BF。


1
这意味着输入已损坏...没有更多信息,我无法提供更多解释。 - skaffman
添加了更多信息。这有任何意义吗?谢谢你的帮助! - Marcus Leon
1
你能否发布包含有问题文本的XML文件部分。 - ChrisF
@Marcus:你能否也发布 <?xml ...?> 头部和有问题部分的十六进制表示? - axtavt
3个回答

3
您的问题是JAXB将没有 <?xml ...?> 头的XML文件视为UTF-8编码,而您的文件使用其他编码(可能是ISO-8859-1或Windows-1252,如果0xBF字符实际上意味着¿)。
如果您可以更改文件的生成器,您可以添加具有实际编码规范的<?xml ...?>头,或者仅使用UTF-8编写文件。
如果您无法更改生成器,则必须使用带有显式编码规范的InputStreamReader,因为(不幸的是)JAXB不允许更改其默认编码。
results = (Results) unmarshaller.unmarshal(
   new InputStreamReader(new FileInputStream(inputFile), "ISO-8859-1")); 

然而,这种解决方案是脆弱的 - 它在具有不同编码规范的 <?xml ...?> 头文件的输入文件上失败。

谢谢,我会尝试。请注意,当我使用Xalan/Java尝试使用XSLT格式化XML文件时,我遇到了同样的错误。Xalan是否也假定UTF-8? - Marcus Leon
那很好!请注意,此代码仅在永远不会有XML头的此文件上运行。相对于使用以下方法,这种方法的优势/差异是什么:results = (Results) unmarshaller.unmarshal(new FileReader(inputFile)); - Marcus Leon
1
@Marcus:FileReader 使用系统默认编码,而 InputStreamReader 使用显式指定的编码。 - axtavt
@axtavt:谢谢...这个对我也有用..不过,um.unmarshall(new InputStreamReader(new ByteArrayInputStream(xml.getBytes()), Charset.forName("UTF-8"))) ..... 这个可以解析字符串而不管xml中是否存在带有UTF-8的头。为什么?另外,之前使用 um.unmarshall(new SAXSource(new InputSource(new ByteArrayInputStream(xml.getBytes())))) 时无法工作...您能解释一下原因吗? - Abhishek Chatterjee

1

这很可能是一个字节顺序标记(BOM),它是UTF文件开头的特殊字节序列。它们实在是让人头疼,尤其是在与.NET系统交互时似乎特别常见。

尝试重新编写您的代码,使用Reader而不是InputStream

results = (Results) unmarshaller.unmarshal(new FileReader(inputFile));

Reader 是 UTF-8 感知的,可能更好地处理它。更简单地,直接将 File 传递给 Unmarshaller,让 JAXBContext 来处理它:

results = (Results) unmarshaller.unmarshal(inputFile);

我可以尝试一下。请注意文件中有两个这样的字符 - 请参阅帖子的第二次更新。 - Marcus Leon
使用 FileReader 看起来不错。当我只指定了 File 时,遇到了相同的错误。我将验证所有的结果,但这看起来很好! - Marcus Leon
但据我理解,这些只是“奇怪”的字符,而不是“字节顺序标记”,对吧?为什么它们会引起这样的麻烦呢? - Marcus Leon
@Marcus:嗯,BOM确实是一系列奇怪的字符,取决于你如何看待它们。 - skaffman

0

听起来你的XML是用UTF-16编码的,但这个编码没有传递给Unmarshaller。使用Marshaller时,您可以使用marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-16");设置它,但由于Unmarshaller不需要支持任何属性,我不确定如何强制执行,除非确保您的XML文档在初始的<?xml?>元素中具有encoding="UTF-16"


1
它不能是UTF-16——尝试将UTF-16编码的XML文件解析为UTF-8将由于错误的标记而失败。它可能是某种单字节编码。 - axtavt
你是正确的。我看了不同的编码,搞混了。 - Andy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接