11

我在 UTF-8 ( )中有一个String包含二进制文件的二进制文件。JAXB 愉快地编组包含此类字符的 XML 文档,但随后无法解组:0"A\u0000B"

final JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
final Marshaller marshaller = jaxbContext.createMarshaller();
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

Root root = new Root();
root.value = "A\u0000B";

final ByteArrayOutputStream os = new ByteArrayOutputStream();
marshaller.marshal(root, os);

unmarshaller.unmarshal(new ByteArrayInputStream(os.toByteArray()));

根类很简单:

@XmlRootElement
class Root { @XmlValue String value; }

输出 XML 包含和之间的二进制以及0(十六进制:),这会在解组期间导致以下错误:AB41 00 42

org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 63; 
An invalid XML character (Unicode: 0x0) was found in the element content of the document.

有趣的是,使用原始 DOM API ( example ) 会产生 escaped 0:A�B但尝试读回它会产生类似的错误。此外,任何 XML 解析器或(另请参见:Python + Expat: Error on entity0 )都不允许(二进制或转义)。xmllint

我的问题:

但是,Java 中成熟的 XML 堆栈(我使用的是 1.7.0_05)不应该默认或通过一些简单的设置来处理这个问题吗?我正在寻找转义、忽略或快速失败 - 但生成无效 XML 的默认行为是不可接受的。我相信这样的基本功能不需要在客户端进行任何额外的编码。

4

1 回答 1

3

为什么 JAXB/DOM API 允许创建无法读取的无效 XML 文档?它不应该在编组期间快速失败吗?

  1. 您需要询问实施者。

  2. 他们可能认为检查每个序列化的数据字符的费用是不合理的......特别是如果解析器随后将再次检查它们。

  3. 决定以这种方式实现序列化程序(或者只是错误地这样做),如果他们随后更改行为以默认进行严格检查,他们将破坏依赖于能够序列化非法 XML 的现有代码。

但是,Java 中成熟的 XML 堆栈(我使用的是 1.7.0_05)不应该默认或通过一些简单的设置来处理这个问题吗?

不一定...如果您接受上述原因#2。即使是简单的设置也会对性能产生可衡量的影响。


此外,任何 XML 解析器或 xmllint 都不允许 0(既不是二进制也不是转义)...

完全正确!XML 规范禁止这样做。

然而,一个更有趣的测试是看看当您尝试使用其他 XML 堆栈生成包含非法字符的 XML 时会发生什么。


有一些优雅的全球解决方案吗?

如果您要解决的问题是如何发送\u0000or ,那么您需要在将字符串插入 DOM之前\u000B对字符串应用一些特定于应用程序的编码。而另一端需要部署等效解码。

如果您要解决的问题是如何在为时已晚之前检测到错误数据,您可以在序列化器和最终输出流之间使用输出流过滤器来做到这一点。但是,如果您检测到错误,就没有好的(即对 XML 使用者透明)方法来修复它。

于 2012-10-08T10:42:45.403 回答