Reputation: 304
I have following schema
<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 generates BookShelf class with two lists, one for newBook and one for oldBook. Excellent!
Now I want books to appear in any order. So I rewrite my schema to:
<complexType name="BookShelf">
<sequence>
<choice minOccurs="0" maxOccurs="unbounded">
<element name="newBook" type="string"/>
<element name="oldBook" type="string"/>
</choice>
</sequence>
</complexType>
But now XJC generates BookShelf with only one list newBookOrOldBook of type List<JAXBElement<String>>
.
I don't care about the order in which books appear and I want to allow XML writer to specify books in any order he\she wishes, but I still want books of each type as List in generated BookShelf class. Is there any way I can achieve this?
Upvotes: 5
Views: 12635
Reputation: 43651
You can use the Simplify plugin from JAXB2 Basics. It can simplify @XmlElements
and @XmlElementRefs
properties, which makes things a lot easier, if you don't really care about the order. Here's an example (excerpt from the documentation):
Consider the following choice:
<xs:complexType name="typeWithReferencesProperty">
<xs:choice maxOccurs="unbounded">
<xs:element name="a" type="someType"/>
<xs:element name="b" type="someType"/>
</xs:choice>
</xs:complexType>
This will normally generate a property like:
@XmlElementRefs({
@XmlElementRef(name = "a", type = JAXBElement.class),
@XmlElementRef(name = "b", type = JAXBElement.class)
})
protected List<JAXBElement<SomeType>> aOrB;
You can use the simplify:as-element-property
element to remodel this complex property as two element properties or simplify:as-reference-property
as two reference properties.
Not that in the case of a reference property, you have to customize one of the xs:element
and not the 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>
Results in:
@XmlElement(name = "a")
protected List<SomeType> a;
@XmlElement(name = "b")
protected List<SomeType> b;
Upvotes: 2
Reputation: 304
I think I have to refuse the idea of mixing lists of different elements in one element (mixing old and new books on a bookself), especially because I'm planning to reference lists of those elements (new and old books lists) in other elements. If I don't it quickly became a nightmare in java code. I ended with the following schema:
<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>
Thanks everyone for helping me realize this. This schema will lead to more clear and simple Java code as well as to more readable and predictable XML document.
Upvotes: -1
Reputation: 12187
I don't think this is possible in JAXB, without writing some custom java or XSLT.
JAXB isn't very good at mapping between objects and xml that have different structure, like yours. Also, the ordering of the old book with respect to new books in XML would be lost when converted to two separate lists in Java, and JAXB generally wants to preserve information.
The following does not answer your question, but maybe it's a step towards what you want:
<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>
I haven't tried this with JAXB, but I think it will generate a list of a class with two fields, newBook and oldBook. So, you don't have to cast or use instanceof, but can just check for null to see which one it is. As I said, it's not a solution, but maybe a little bit closer.
Upvotes: 0
Reputation: 192417
Maybe something like this?
<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>
Of course you could simplify to
<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>
Upvotes: 0