此问题有一种解决方法。更具体地说,您需要做的是:
1.为PartB.xsd(无命名空间定义)定义代理架构(PartB_proxy.xsd)并指定临时命名空间(例如PartB强>):
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns="PartB"
targetNamespace="PartB">
<xsd:include schemaLocation="partB.xsd"/>
2.准备绑定文件(对于大型架构,此步骤可以通过生成剧集文件来自动化 - 我的文章中的更多详细信息 - 我在本文末尾附加了链接) - 需要此步骤以避免生成重复的类对于 PartB 架构(默认情况下,将为 PartA 和 PartC 架构/java 包生成来自 PartB 架构的重复类):
<bindings version="2.1" xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<bindings scd="x-schema::partA" xmlns:partA="PartA">
<bindings scd="~partA:SomeType1">
<class ref="SomeType1"/>
</bindings>
<bindings scd="~partA:SomeType2">
<class ref="SomeType2"/>
</bindings>
</bindings>
<bindings scd="x-schema::partC" xmlns:partC="PartC">
<bindings scd="~partC:SomeType1">
<class ref="SomeType1"/>
</bindings>
<bindings scd="~partC:SomeType2">
<class ref="SomeType2"/>
</bindings>
</bindings>
</bindings>
3.使用 XJC 生成 JAXB 类,例如 Gradle 任务(我使用的是 Moxy 实现,但您可以使用 JDK 8 中的默认 XJC 生成器或独立 JAXB 库用于更新的 JDK 版本):
task generateExampleChameleonSourcesWithMoxy(type: JavaExec) {
classpath = configurations.moxy
main = 'org.eclipse.persistence.jaxb.xjc.MOXyXJC'
args '-b'
args 'src/main/resources/example/chameleon/bindings.xml'
args '-d'
args 'src/main/generated'
args 'src/main/resources/example/chameleon/PartA.xsd'
args 'src/main/resources/example/chameleon/PartB_proxy.xsd'
args 'src/main/resources/example/chameleon/PartC.xsd'
}
4.从 package-info.java 中删除为 partB 模式生成的代理命名空间(partB):
javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package partB;
5.最后,您可以使用 Default Namespace Remapping 技术编组和解组这些 XML 文档:
这是负责该操作的代码(JDK 1.8):
//Initialize JaxbContext
Map<String, String> properties = new HashMap<>();
properties.put("com.sun.xml.internal.bind.defaultNamespaceRemap", "partC");
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{SomeType1.class}, properties);
//Unmarshall Message object file from example XML
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object messageObject = unmarshaller.unmarshal(getClass().getResourceAsStream("/example/chameleon/Division.xml"));
//Marshall message object back into XML
ByteArrayOutputStream xmlMessageOS = new ByteArrayOutputStream();
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(messageObject, xmlMessageOS);
System.out.println(xmlMessageOS.toString());
//Validate output XML with schema
InputStream xmlInputStream = new ByteArrayInputStream(xmlMessageOS.toByteArray());
Source xmlSource = new StreamSource(xmlInputStream);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(getClass().getResource("/example/chameleon/PartC.xsd"));
Validator validator = schema.newValidator();
validator.validate(xmlSource);`
不幸的是,对于来自 PartA 和 PartC 命名空间的 JAXB 对象,您必须使用不同的 JAXB 上下文。这是必需的,因为 JAXB 默认命名空间重新映射属性是根据 JAXB 上下文设置的 - 这样 JAXB 编组器/解组器就知道如何处理没有定义命名空间的 POJO 对象(PartB)。
不过,我认为这不是问题,因为通常所有 JAXB 上下文都被初始化一次 - 在应用程序启动期间(在单例中)。
总而言之,上述解决方法允许您使用 JAXB 编组/解组 XML 文档,而无需修改变色龙模式。代理 XSD 文件仅在开始时使用 - 用于生成 JAXB 对象 (XJC) 的过程。编组/未编组的 XML 文档仍然符合原始模式。这种技术特别有用,如果您不允许修改模式。我正在为http://www.iata.org定义的18.1版本中的只读NDC标准(模式集)处理这个问题。
我写过一篇关于该主题的文章:如何在 JAXB 中处理 Chameleon 命名空间设计。你会在这里找到它:https://medium.com/@pziobron/how-to-deal-with-chameleon-namespace-design-in-jaxb-e36bcc03767d。希望您会发现它很有用。