在xs:choice中两次使用相同的字段名称时,如何使用JAXB从XSD文件生成Java?

时间:2018-07-06 00:17:32

标签: java xml xsd jaxb

我有一个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;
}

我原本希望每个属性都能有一个吸气剂,但我却遇到了这场噩梦。

这是因为在模式的2个不同部分中使用了OBJECTDESCR,这是正确的。通常,我只会使用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。

2 个答案:

答案 0 :(得分:0)

免责声明::我是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代码生成中。参见this guide。使用时,它将类似于:

        <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

答案 1 :(得分:0)

有人在这里发布了答案,说我应该在我的bindings.xjb中尝试这样的事情:

<jxb:bindings 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    version="2.1">
    <jxb:bindings>
        <jxb:globalBindings choiceContentProperty="true"/>
    </jxb:bindings>
</jxb:bindings>

我不知道答案在哪里,但是我尝试了它的建议并奏效了。它运行得非常好,我已经能够删除我拥有的所有其他jxb:bindings。因此,无论是谁。那将是我接受的答案。