5

我有以下架构

<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 只有一个类型为 newBookOrOldBook 的列表List<JAXBElement<String>>

我不关心书籍出现的顺序,我想允许 XML 编写器按照他\她希望的任何顺序指定书籍,但我仍然希望每种类型的书籍作为生成的 BookShelf 类中的列表。有什么办法可以做到这一点?

4

4 回答 4

2

您可以使用JAXB2 Basics中的Simplify 插件。如果您并不真正关心顺序,它可以简化和属性,这会使事情变得容易得多。这是一个示例(摘自文档):@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;
于 2012-03-26T12:46:31.213 回答
0

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

JAXB 不太擅长在具有不同结构的对象和 xml 之间进行映射,例如您的。此外,当在 Java 中转换为两个单独的列表时,旧书相对于新书的排序将丢失,而 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 试过这个,但我认为它会生成一个包含两个字段的列表, newBookoldBook。因此,您不必强制转换或使用 instanceof,而只需检查 null 以查看它是哪一个。正如我所说,这不是一个解决方案,但可能更接近一点。

于 2009-05-21T13:05:25.047 回答
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>
于 2009-05-20T17:15:51.333 回答
-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 文档。

于 2009-05-21T15:38:34.177 回答