JAXB选择清单

时间:2009-05-20 16:00:17

标签: xsd jaxb xjc

我有以下架构

<complexType name="BookShelf">
   <sequence>
      <element name="newBook" type="string" minOccurs="0" maxOccurs="unbounded"/>
      <element name="oldBook" type="string" minOccurs="0" maxOccurs="unbounded"/>
   </sequence>
</complexType>

XJC生成带有两个列表的BookShelf类,一个用于newBook,另一个用于oldBook。优良!

现在我希望书籍以任何顺序出现。所以我将我的架构重写为:

<complexType name="BookShelf">
   <sequence>
      <choice minOccurs="0" maxOccurs="unbounded">
         <element name="newBook" type="string"/>
         <element name="oldBook" type="string"/>
      </choice>
   </sequence>
</complexType>

但是现在XJC生成的BookShelf只有一个类型List<JAXBElement<String>>的newBookOrOldBook列表。

我不关心书籍出现的顺序,我想让XML编写者按照他希望的任何顺序指定书籍,但我仍然希望在生成的BookShelf类中将每种类型的书籍作为List。有什么方法可以实现这个目标吗?

4 个答案:

答案 0 :(得分:2)

您可以使用Simplify plugin中的JAXB2 Basics。它可以简化@XmlElements@XmlElementRefs属性,如果您不关心订单,这会使事情变得更容易。这是一个例子(摘自文档):

考虑以下选择:

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

这通常会生成如下属性:

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

您可以使用simplify:as-element-property元素将此复杂属性重新编码为两个元素属性,或simplify:as-reference-property作为两个参考属性。

如果是引用属性,则必须自定义xs:element之一,而不是xs:choice

<xs:complexType name="typeWithReferencesProperty">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="a" type="someType">
            <xs:annotation>
                <xs:appinfo>
                    <simplify:as-element-property/>
                </xs:appinfo>
            </xs:annotation>
        </xs:element>
        <xs:element name="b" type="someType"/>
    </xs:choice> 
</xs:complexType>

结果:

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

答案 1 :(得分:0)

也许是这样的?

<schema 
   elementFormDefault = "qualified" 
   xmlns              = "http://www.w3.org/2001/XMLSchema"
   xmlns:xs           = "http://www.w3.org/2001/XMLSchema"
   xmlns:tns          = "urn:cheeso.examples.2009.05.listofbooks" 
   targetNamespace    = "urn:cheeso.examples.2009.05.listofbooks" 
  >

  <element name="Shelf" nillable="true" type="tns:BookShelf" />

  <complexType name="BookShelf">
    <sequence>
      <element minOccurs="0" maxOccurs="1" name="Store" type="tns:ArrayOfChoice1" />
    </sequence>
  </complexType>

  <complexType name="ArrayOfChoice1">
    <choice minOccurs="0" maxOccurs="unbounded">
      <element minOccurs="1" maxOccurs="1" name="newBook" nillable="true" type="tns:newBook" />
      <element minOccurs="1" maxOccurs="1" name="oldBook" nillable="true" type="tns:oldBook" />
    </choice>
  </complexType>

  <complexType name="Book">
    <attribute name="name" type="string" />
  </complexType>

  <complexType name="newBook">
    <complexContent mixed="false">
      <extension base="tns:Book" />
    </complexContent>
  </complexType>

  <complexType name="oldBook">
    <complexContent mixed="false">
      <extension base="tns:Book" />
    </complexContent>
  </complexType>

</schema>

当然你可以简化为

<schema 
   elementFormDefault = "qualified" 
   xmlns              = "http://www.w3.org/2001/XMLSchema"
   xmlns:xs           = "http://www.w3.org/2001/XMLSchema"
   xmlns:tns          = "urn:cheeso.examples.2009.05.listofbooks" 
   targetNamespace    = "urn:cheeso.examples.2009.05.listofbooks" 
  >

  <element name="Shelf" nillable="true" type="tns:BookShelf" />

  <complexType name="BookShelf">
    <sequence>
      <element minOccurs="0" maxOccurs="1" name="Store" type="tns:ArrayOfChoice1" />
    </sequence>
  </complexType>

  <complexType name="ArrayOfChoice1">
    <choice minOccurs="0" maxOccurs="unbounded">
      <element minOccurs="1" maxOccurs="1" name="newBook" nillable="true" type="xs:string" />
      <element minOccurs="1" maxOccurs="1" name="oldBook" nillable="true" type="xs:string" />
    </choice>
  </complexType>

</schema>

答案 2 :(得分:0)

如果没有编写自定义java或XSLT,我认为这在JAXB中是不可能的。

JAXB不擅长在具有不同结构的对象和xml之间进行映射,就像你的一样。此外,当使用Java转换为两个单独的列表时,旧书与XML中的新书的排序将会丢失,而JAXB通常希望保留信息。

以下回答你的问题,但也许这是你想要的一步:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="bookShelf" type="BookShelf"/>
  <xs:complexType name="BookShelf">
    <xs:sequence>
      <xs:sequence minOccurs="0" maxOccurs="unbounded">
        <xs:element name="newBook" minOccurs="0" type="xs:string"/>
        <xs:element name="oldBook" minOccurs="0" type="xs:string"/>
      </xs:sequence>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

我没有尝试使用JAXB,但我认为它会生成列表,其中包含两个字段 newBook oldBook 。因此,您不必强制转换或使用instanceof,但只需检查null即可查看它是哪一个。正如我所说的那样,不是解决方案,但可能会更接近。

答案 3 :(得分:-1)

我想我必须拒绝在一个元素中混合使用不同元素的列表(在书本上混合旧书和新书)的想法,特别是因为我打算引用这些元素的列表(新旧书籍列表)在其他元素。如果我不这样做很快就成了java代码的噩梦。我以下面的架构结束了:

<schema
   xmlns="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://www.example.org/books"
   targetNamespace="http://www.example.org/books"
   elementFormDefault="qualified"
>
   <complexType name="BookShelf">
      <sequence>
         <element name="newBooks" type="tns:NewBookList" minOccurs="0" />
         <element name="oldBooks" type="tns:OldBookList" minOccurs="0" />
      </sequence>
   </complexType>

   <complexType name="NewBookList">
      <sequence>
         <element name="newBook" type="tns:NewBook" maxOccurs="unbounded" />
      </sequence>
   </complexType>

   <complexType name="OldBookList">
      <sequence>
         <element name="oldBook" type="tns:OldBook" maxOccurs="unbounded" />
      </sequence>
   </complexType>

   <complexType name="NewBook" />
   <complexType name="OldBook" />
</schema>

感谢大家帮助我实现这一目标。这种模式将导致更清晰简单的Java代码以及更易读和可预测的XML文档。