我有以下架构
<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。有什么方法可以实现这个目标吗?
答案 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文档。