JAXB和无命名空间的XML

Mar*_*idt 5 java xml jaxb xjc

供应商提供的XML如下所示:

<?xml version="1.0" encoding="utf-8"?>
<Foo>
  <Bar>...</Bar>
  <Bar>...</Bar>
</Foo>
Run Code Online (Sandbox Code Playgroud)

请注意,没有xmlns="..."声明,供应商也不提供架构.这是无法更改的,供应商将来会继续像这样发布XML.

为了生成JAXB绑定,我创建了一个这样的模式:

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://acme.com/schema"
            xmlns:tns="http://acme.com/schema"
            elementFormDefault="qualified">
    <xsd:element name="Foo">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element ref="tns:Bar" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="Bar">
        ...
    </xsd:element>
</xsd:schema>
Run Code Online (Sandbox Code Playgroud)

请注意,我已经声明了一个或多或少有意义的命名空间(" http://acme.com/schema "),以便它可以用于元素引用等.XJC生成以下内容package-info.java:

@javax.xml.bind.annotation.XmlSchema(namespace = "http://acme.com/schema", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.acme.schema;
Run Code Online (Sandbox Code Playgroud)

然后我尝试解组XML文档:

JAXBContext jaxb = JAXBContext.newInstance("com.acme.schema");
Unmarshaller unmarshaller = jaxb.createUnmarshaller();
InputStream is = this.getClass().getClassLoader().getResourceAsStream("test.xml");

InputSource source = new InputSource(is);
Foo foo = (Foo) unmarshaller.unmarshal(source);
Run Code Online (Sandbox Code Playgroud)

这是我得到的例外:

javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"Foo"). Expected elements are <{http://acme.com/schema}Foo>,...>
Run Code Online (Sandbox Code Playgroud)

显然,这是因为XML元素属于空命名空间,而JAXB类具有非空元素.

有没有办法伪造XML命名空间(可能在XML解析期间),以便JAXB识别元素并成功绑定它们?SAX/StAX解决方案比DOM更受欢迎,因为XML文档可能相当庞大.

Pac*_*ace 2

首先,我不会推荐所有这些。与第三方 API 集成已经足够复杂,无需增加额外的复杂性。为什么要费心添加命名空间呢?我不确定你能从中得到什么。想象一下能够继承您的代码库的幸运者。他们会看到命名空间的添加,但不知道为什么要这样做。

我什至会更进一步,建议完全避免该模式,而只使用带注释的 POJO。所有这些步骤只会增加复杂性、构建步骤等。

但是,如果您下定决心,这似乎是 XSL 转换的典型情况。您可以找到一个可以轻松添加名称空间的 XSL 转换,例如这个问题 然后将您的转换连接到 JAXB 中就是一个简单的问题...

private static Foo unmarshalDocument(InputStream xslStream, InputStream xmlStream) throws Exception {
    StreamSource stylesource = new StreamSource(xslStream); 
    StreamSource inputStream = new StreamSource(xmlStream);
    Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
    JAXBResult result = new JAXBResult(context);
    transformer.transform(inputStream, result);
    return (Foo) result.getResult();
}
Run Code Online (Sandbox Code Playgroud)