首页 > 解决方案 > 当在 xs:choice 中使用两次相同的字段名称时,如何使用 JAXB 从 XSD 文件生成 java?

问题描述

我有一个 Java maven 项目,需要从一组 XSD 文件中生成 Java 类。我正在使用 jaxb2-maven-plugin 2.4。XSD 文件之一包含以下代码段:

<xs:choice>
    <xs:sequence>
        <xs:element name="LOT_DIVISION" type="lot_division_f01"/>
        <xs:element name="OBJECT_DESCR" type="object_f01"/>
    </xs:sequence>
    <xs:sequence>
        <xs:element ref="NO_LOT_DIVISION"/>
        <xs:element name="OBJECT_DESCR" type="object_f01"/>
    </xs:sequence>
</xs:choice>

当我尝试为此使用 JAXB 自动生成 Java 类时,我最终得到如下结果:

/**
 * Gets the rest of the content model. 
 * 
 * <p>
 * You are getting this "catch-all" property because of the following reason: 
 * The field name "OBJECTDESCR" is used by two different parts of a schema. See: 
 * line 142 of file:/C:/Projects/main/web/service/src/xsd/ted/209/F01_2014.xsd
 * line 138 of file:/C:/Projects/main/web/service/src/xsd/ted/209/F01_2014.xsd
 * <p>
 * To get rid of this property, apply a property customization to one 
 * of both of the following declarations to change their names: 
 * Gets the value of the content property.
 * 
 * <p>
 * This accessor method returns a reference to the live list,
 * not a snapshot. Therefore any modification you make to the
 * returned list will be present inside the JAXB object.
 * This is why there is not a <CODE>set</CODE> method for the content property.
 * 
 * <p>
 * For example, to add a new item, do as follows:
 * <pre>
 *    getContent().add(newItem);
 * </pre>
 * 
 * 
 * <p>
 * Objects of the following type(s) are allowed in the list
 * {@link JAXBElement }{@code <}{@link TextFtSingleLine }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link CpvSet }{@code >}
 * {@link JAXBElement }{@code <}{@link TypeContract }{@code >}
 * {@link JAXBElement }{@code <}{@link TextFtMultiLines }{@code >}
 * {@link JAXBElement }{@code <}{@link Val }{@code >}
 * {@link JAXBElement }{@code <}{@link LotDivisionF01 }{@code >}
 * {@link JAXBElement }{@code <}{@link ObjectF01 }{@code >}
 * {@link JAXBElement }{@code <}{@link Empty }{@code >}
 * {@link JAXBElement }{@code <}{@link XMLGregorianCalendar }{@code >}
 * 
 * 
 */
public List<JAXBElement<?>> getContent() {
    if (content == null) {
        content = new ArrayList<JAXBElement<?>>();
    }
    return this.content;
}

我期待每个属性都有一个吸气剂,但我却得到了这个包罗万象的噩梦。

它说这是因为 OBJECTDESCR 用于模式的 2 个不同部分,这是正确的。通常我只会使用 bindings.xjb 重命名一个或另一个,但我不知道在这种情况下如何。

XML 数据和 XSD 文件来自http://ftp.ted.europa.eu/TED/main/HomePage.do所以我对这些部分几乎没有控制权。但我需要阅读他们的数据。

XSD 文件的完整集合可在此处获得:http : //publications.europa.eu/mdr/resource/eprocurement/ted/R2.0.9/publication/latest/ 片段来自 F01_2014.xsd。

标签: javaxmlxsdjaxb

解决方案


免责声明:我是可以完成这项工作的JAXB2 Simplify Plugin的作者。

让我们从 MCVE 开始:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="choice" type="choiceType"/>
    <xs:complexType name="choiceType">
        <xs:choice>
            <xs:sequence>
                <xs:element name="x" type="xs:string"/>
                <xs:element name="z" type="xs:string"/>
            </xs:sequence>
            <xs:sequence>
                <xs:element name="y" type="xs:string"/>
                <xs:element name="z" type="xs:string"/>
            </xs:sequence>
        </xs:choice>
    </xs:complexType>
</xs:schema>

这会产生如下代码:

@XmlElementRefs({
    @XmlElementRef(name = "x", type = JAXBElement.class, required = false),
    @XmlElementRef(name = "z", type = JAXBElement.class, required = false),
    @XmlElementRef(name = "y", type = JAXBElement.class, required = false)
})
protected List<JAXBElement<String>> xAndZOrY;

虽然从建模的角度来看,这段代码可能更好,但它看起来很奇怪,大多数开发人员更喜欢更简单的代码。像三个独立的属性xyz

为此,您可以使用JAXB2 Simplify Plugin。就是这样。

首先,将JAXB2 Simplify Plugin添加到您的 JAXB 代码生成中。请参阅本指南。使用这将如下所示:

        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <version>0.14.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <args>
                    <arg>-Xsimplify</arg>
                </args>
                <plugins>
                    <plugin>
                        <groupId>org.jvnet.jaxb2_commons</groupId>
                        <artifactId>jaxb2-basics</artifactId>
                        <version>0.12.0</version>
                    </plugin>
                </plugins>
            </configuration>
        </plugin>

抱歉,我不会在这里提供其他 JAXB2 Maven 插件的配置(如)。

接下来,您必须为 Simplify 插件指定要简化的属性。这可以直接在模式中完成,也可以(首选方式)通过外部绑定文件完成:

<jaxb:bindings
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:simplify="http://jaxb2-commons.dev.java.net/basic/simplify"
    jaxb:extensionBindingPrefixes="simplify"
    jaxb:version="2.3">

    <jaxb:bindings schemaLocation="schema.xsd" node="/xsd:schema">
        <jaxb:bindings node="xsd:complexType[@name='choiceType']">
            <simplify:property name="xAndZOrY">
                <simplify:as-element-property/>
            </simplify:property>
        </jaxb:bindings>
    </jaxb:bindings>
</jaxb:bindings>

这将产生以下代码:

protected List<String> x;
protected List<String> z;
protected List<String> y;

public List<String> getX() { ... }

public List<String> getZ() { ... }

public List<String> getY() { ... }

您可以在此处找到完整的工作示例:

https://github.com/highsource/jaxb2-basics-support/tree/master/s/simplify-choice


推荐阅读