我必须整理我的根 xml 对象的片段:
Header header = ebicsNoPubKeyDigestsRequest.getHeader();
JAXBElement<org.ebics.h003.EbicsNoPubKeyDigestsRequest.Header> jaxbElement =
new JAXBElement<EbicsNoPubKeyDigestsRequest.Header>(
new QName("header"), EbicsNoPubKeyDigestsRequest.Header.class, header);
byte[] headerXml = JAXBHelper.marshall(jaxbElement, true);
但是当我编码 ebicsNoPubKeyDigestsRequest
时,命名空间不一样(在 header 片段中我有:xmlns:ns4="http://www.ebics.org/H003"
但在 ebicsNoPubKeyDigestsRequest
我有 xmlns="http://www.ebics.org/H003"
)
如果我直接编码 header 对象,而不使用 JAXBElement,则会出现 No @XmlRootElement
错误
我怎样才能拥有相同的命名空间?
注意:我已经使用了 NamespacePrefixMapper
类:
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
@Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
if (namespaceUri.equals("http://www.ebics.org/H003")) {
return "";
} else if (namespaceUri.equals("http://www.w3.org/2000/09/xmldsig#")) {
return "ds";
} else if (namespaceUri.equals("http://www.ebics.org/S001")) {
return "ns1";
} else if (namespaceUri.equals("http://www.w3.org/2001/XMLSchema-instance")) {
return "ns2";
}
return "";
}
});
编辑: 这里是不同的 package-info.java:
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.ebics.org/H003", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.ebics.h003;
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.ebics.org/S001", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.ebics.s001;
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.w3.org/2000/09/xmldsig#", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.w3._2000._09.xmldsig_;
最佳答案
在没有看到您实际的 XML 模式、文件和 JAXB 生成的类(及其注释)的情况下,我只能建议您尝试根据您的场景调整以下示例。
假设您有一个 JAXB 生成的类,如下所示:
@XmlRootElement(namespace = "http://test.com")
@XmlType(namespace = "http://test.com")
public static final class Test {
public String data;
public Test() {}
}
在包裹中test
还有一个package-info.java
像这样在其中文件:
@XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED,
xmlns = @XmlNs(prefix = "", namespaceURI = "http://test.com"))
package test;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
以下代码:
Test test = new Test();
test.data = "Hello, World!";
JAXBContext context = JAXBContext.newInstance(Test.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(test, System.out);
将打印这个:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<test xmlns="http://test.com">
<data>Hello, World!</data>
</test>
您或许可以省略 NamespacePrefixMapper
完全实现。
尝试省略特定的 namespace
来自任何注释的元素,并查看输出如何变化。
Blaise Doughan (一位 Java XML 绑定(bind)专家,可能潜伏在附近 的某个地方)在他的博客上发布了一些关于此问题的信息,请参阅 his post了解更多信息。
根据 Baptiste 在聊天中提供的意见,我提出了以下解决方案(我认为这是最轻松的)。
正常使用 XJC 编译模式文件 ($ xjc .
)。这将生成 package-java.info
每个生成的包的文件。我假设此架构不会每天更新,因此您可以安全地对 package-info.java
进行修改文件(即使这些文件中会有一些行注释告诉你不要这样做——无论如何都要这样做)。如果架构得到更新并且您必须重新编译它,请使用 -npa
运行 XJC开关,告诉它不要生成那些 package-info.java
自动生成文件,因此(理想情况下)您不能覆盖您手工制作的文件(如果您使用版本控制,您可以/应该将这些(手工制作的)文件包含在存储库中)。
基于提供的架构文件生成了四个包,因此我将包含我的修改版本 package-info.java
文件。
@XmlSchema(namespace = "http://www.ebics.org/H000",
xmlns = @XmlNs(prefix = "ns1",
namespaceURI = "http://www.ebics.org/H000"))
package org.ebics.h000;
@XmlSchema(namespace = "http://www.ebics.org/H003",
xmlns = @XmlNs(prefix = "",
namespaceURI = "http://www.ebics.org/H003"))
package org.ebics.h003;
@XmlSchema(namespace = "http://www.ebics.org/S001",
xmlns = @XmlNs(prefix = "ns3",
namespaceURI = "http://www.ebics.org/S001"))
package org.ebics.s001;
@XmlSchema(namespace = "http://www.w3.org/2000/09/xmldsig#",
xmlns = @XmlNs(prefix = "ns2",
namespaceURI = "http://www.w3.org/2000/09/xmldsig#"))
package org.w3._2000._09.xmldsig;
在此之后你创建你的 JAXBContext
像这样:
JAXBContext context =
JAXBContext.newInstance("org.ebics.h003:org.ebics.s001:org.w3._2000._09.xmldsig");
(我注意到您实际上并没有使用 h000
包,所以我从包名称列表中省略了它。如果包含它,那么编码的 XML 的根标记可能包含它的命名空间和前缀映射,即使它没有被使用。)
在此之后,您解码输入的 XML 并对内存中的对象执行任何您想做的事情。
Unmarshaller unmarshaller = context.createUnmarshaller();
EbicsNoPubKeyDigestsRequest ebicsNoPubKeyDigestsRequest =
(EbicsNoPubKeyDigestsRequest) unmarshaller.unmarshal(stream);
现在,如果您只想编码 header
嵌套在 ebicsNoPubKeyDigestsRequest
内的标签你必须把它包在一个 JAXBElement<...>
里因为header
的类型 EbicsNoPubKeyDigestsRequest.Header
未使用 @XmlRootElement
进行注释注解。您有两种(在这种情况下一种)创建此元素的方法。
创建一个 ObjectFactory
相应包的实例并使用其 JAXBElement<T> createT(T t)
功能。它将其输入包装成 JAXBElement<...>
.然而不幸的是,对于 header
字段的类型(给定您的架构文件)XJC 不生成此类方法,因此您必须手动完成。
基本上您几乎已经做对了,但是在创建 JAXBElement<...>
时而不是通过它 new QName("header")
您必须创建一个完全限定的名称,这意味着也指定了 namespace 。仅传递 XML 标记的名称是不够的,因为 JAXB 不会以这种方式知道这个特定的 header
。标签是 "http://www.ebics.org/H003"
的一部分命名空间。所以这样做:
QName qualifiedName = new QName("http://www.ebics.org/H003", "header");
JAXBElement<EbicsNoPubKeyDigestsRequest.Header> header =
new JAXBElement<EbicsNoPubKeyDigestsRequest.Header>(
qualifiedName, EbicsNoPubKeyDigestsRequest.Header.class, header);
我没有测试是否只改变 QName
实例化解决了你的问题,但也许它会。但是我认为它不会,您必须手动管理您的前缀才能获得漂亮和一致的结果。
关于java - 具有不同 namespace 的 JAXB 片段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8560383/