【问题标题】:JAXB and namespace-less XMLJAXB 和无命名空间的 XML
【发布时间】:2016-09-21 00:05:47
【问题描述】:

有这样一个供应商提供的 XML:

<?xml version="1.0" encoding="utf-8"?>
<Foo>
  <Bar>...</Bar>
  <Bar>...</Bar>
</Foo>

请注意,没有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>

请注意,我已经声明了一个或多或少有意义的命名空间(“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;

然后我尝试解组 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);

这是我得到的例外:

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

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

有没有办法伪造一个 XML 命名空间(可能在 XML 解析期间),以便 JAXB 能够识别元素并成功绑定它们? SAX/StAX 解决方案将优于 DOM,因为 XML 文档可能相当庞大。

【问题讨论】:

  • 你介意把 XJC 生成的类放在上面吗?

标签: java xml jaxb xjc


【解决方案1】:

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

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

但是,如果您下定决心,这似乎是 XSL 转换的典型案例。您可以很容易地找到添加命名空间的 XSL 转换,例如 this question 然后将您的转换连接到 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();
}

【讨论】:

  • 确实,命名空间根本不需要。 (进一步阅读:O'Reilly “XML Schema”,第 10 章,“控制命名空间”。)我已经删除了 targetNamespace=xmlns:tns= 属性和 tns: 前缀,问题就消失了。
  • 至于 XJC 与 POJO - 我只展示了 XML 的 sn-p,实际文档要复杂得多;手工制作带注释的 POJO 在这里会有点过头了。相反,我们使用了来自 NetBeans XML Tools 的优秀模式设计器,应用了最少的 JAXB 自定义,然后瞧。这是一个真正的节省时间。至于构建过程,它是由 Maven + maven-jaxb2-plugin 驱动的,所以所有的复杂性都被隐藏了。但是,我记得 XJC 生成的类需要大量手动定制的情况,所以重新生成的想法被拒绝了。
猜你喜欢
  • 2019-05-06
  • 1970-01-01
  • 1970-01-01
  • 2015-04-21
  • 1970-01-01
  • 2014-06-07
  • 2010-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多