我在UTF-8(String
)中有一个0
缩进二进制"A\u0000B"
。 JAXB愉快地编组包含此类字符的XML文档,但后来无法解组它:
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
以及A
和B
之间(十六进制:41 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)会生成转义0
:A�B
,但尝试将其读回会产生类似的错误。任何XML解析器或0
也不允许xmllint
(二进制或转义)(另请参阅:Python + Expat: Error on � entities)。
为什么JAXB / DOM API允许创建无法读回的无效 XML文档?编组时不应该快速失败吗?
有一些优雅的全球解决方案吗?我看到有人通过以下方式解决这个问题:
但是,不应该在Java中成熟的XML堆栈(我使用1.7.0_05)默认处理或者通过一些简单的设置处理它?我正在寻找逃避,忽略或快速失败 - 但生成无效XML的默认行为是不可接受的。我相信这些基本功能不应该在客户端需要任何额外的编码。
答案 0 :(得分:3)
为什么JAXB / DOM API允许创建无法读回的无效XML文档?在编组时不应该快速失败吗?
您需要询问实施者。
他们可能认为检查序列化的每个数据字符的费用是不合理的......特别是如果解析器将再次检查它们。
决定以这种方式实现序列化程序(或者错误地执行了这种方式),如果他们在默认情况下将行为更改为严格检查,则会破坏依赖于能够序列化非法的现有代码XML。
但是,不应该在Java中成熟的XML堆栈(我使用1.7.0_05)默认处理这个或者通过一些简单的设置来处理它?</ p>
不一定......如果您接受上述原因#2。即使是简单的设置也会对性能产生可衡量的影响。
任何XML解析器或xmllint都不允许0(既不是二进制也不是转义)...
非常正确! XML规范禁止使用它。
然而,一个更有趣的测试是看看当你尝试使用其他XML栈生成包含非法字符的XML时会发生什么。
有一些优雅而全球化的解决方案吗?
如果您要解决的问题是如何发送\u0000
或\u000B
,那么您需要在之前将一些特定于应用程序的编码应用于String 将其插入DOM。另一端需要部署等效解码。
如果您要解决的问题是如何在为时已晚之前检测到错误数据,则可以使用序列化程序和最终输出流之间的输出流过滤器来完成此操作。但是如果你发现了这种不好,就没有好办法(即对XML用户透明)修复它。