如何使用JAXB将<xsd:choice/>子元素分离为单独的集合属性?

4

我有下面这个来自供应商的 XSD 片段,我不能改变它的规范:

<xsd:element name="navmap">
  <xsd:complexType>
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
      <xsd:element ref="navitem"/>
      <xsd:element ref="debug"/>
    </xsd:choice>
    <xsd:attribute name="focus" type="xsd:string" use="optional"/>
  </xsd:complexType>
</xsd:element>

现在没有进行定制,它将生成以下代码

@XmlElements({
        @XmlElement(name = "navitem", type = Navitem.class),
        @XmlElement(name = "debug", type = Debug.class)
    })
    protected List<Object> navitemOrDebug;

我希望它能为每种类型生成一个单独的列表,就像下面这样。
@XmlElements({
        @XmlElement(name = "navitem", type = Navitem.class)
    })
    protected List<Navitem> navitems;

@XmlElements({
        @XmlElement(name = "debug", type = Debug.class)
    })
    protected List<Debug> debugs;

我在我的.xjb文件中有以下内容,它可以重命名整个List,但我无法弄清如何将它们分开。

<jxb:bindings node="//xsd:element[@name='navmap']//xsd:complexType//xsd:choice">
  <jxb:property name="contents" />
</jxb:bindings>

我该如何指定在外部的.xjb绑定文件中为每个类型分别创建单独的List或Set?
如果无法这样做,我该如何在.xsd文件中添加jaxb:annotation来为每个类型指定单独的List或Set?
在这种情况下,顺序不重要。
注意:我更喜欢使用外部的.xjb解决方案,我不想针对供应商提供的每个新版本自定义xsd进行差异比较,因为它们太多了。

你不能使用你修改过的供应商XSD吗? - Rostislav Matl
2个回答

2

如承诺一样,请见 Simplify Plugin

该插件可简化“复杂”属性,这些属性通常是从可重复选择中生成的,例如下面的选择:

<xs:complexType name="typeWithReferencesProperty">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="a" type="someType"/>
        <xs:element name="b" type="someType"/>
    </xs:choice> 
</xs:complexType>

...

<xs:complexType name="typeWithElementsProperty">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="a" type="xs:string"/>
        <xs:element name="b" type="xs:int"/>
    </xs:choice> 
</xs:complexType>

默认情况下,XJC将会使用复合属性来建模一个中包含多个引用或元素的结构。

@XmlElementRefs({
    @XmlElementRef(name = "a", type = JAXBElement.class),
    @XmlElementRef(name = "b", type = JAXBElement.class)
})
protected List<JAXBElement<SomeType>> aOrB;

...

@XmlElements({
    @XmlElement(name = "a", type = String.class)
    @XmlElement(name = "b", type = Integer.class),
})
protected List<Serializable> aOrB;

这些复杂的属性是为了充分地模拟XML schema中复杂的内容,即保持可重复选择元素的顺序而必需的。

不幸的是,它们不像bean属性一样习惯用语。这些属性是“异构”的(它们存储不同类型),这使得与它们一起工作变得困难。

然而,如果元素的顺序不重要 - 也就是说,您可以接受在重新封送后它会改变的事实,这些属性的结构可以被简化:复杂属性可以分成几个简单属性。

简化插件实现了这个任务。它允许您简化您的复杂属性。插件将删除复杂属性,并插入几个更简单的属性代替原始(复杂)属性。所以您可以得到类似于:

@XmlElement(name = "a", type = String.class)
protected List<String> a;
@XmlElement(name = "b", type = Integer.class)
protected List<Integer> b;

或者:

@XmlElement(name = "a")
protected List<SomeType> a;
@XmlElement(name = "b")
protected List<SomeType> b;

或者:

@XmlElementRef(name = "a", type = JAXBElement.class)
protected List<JAXBElement<SomeType>> a;
@XmlElementRef(name = "b", type = JAXBElement.class)
protected List<JAXBElement<SomeType>> b;

根据定制需求。

插件将在JAXB2 Basics 0.6.3中发布,现在可以从此存储库中获取快照。


0
据我所知,目前你无法使用JAXB RI中的XJC实现此功能。理论上,可以编写一个插件来更改XJC模型。
但是你必须意识到,两个单独的同类属性debugnavitem不能等同于一个异类属性navitemOrDebug。也就是说,如果你对同一对象进行反序列化和序列化,元素的顺序将会不同。
然而,在许多情况下,这可能是有意义的。请在这里提交问题,我会考虑实现它。

感谢您的考虑,我已在提供的链接中创建了一个问题。 - user177800

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接