There have been a lot of similar questions which focus on one aspect to optimize but each solution had an ugly downside.
Suppose I want to develop an XML schema (XSD) which allows the following documents and want to generate classes using XJC:
<Catalogue>
<Book>...</Book>
<Journal>...</Journal>
<Book>...</Book>
...
</Catalogue>
The schema should model the type hierarchy (Book
and Journal
are subclasses of Publication
). Naturally, this should also
be the case for the generated Java classes.
I tried the following approches which all have a major issue:
1.) modeling Catalogue to contain a xsd:choice
of all possible subtypes.
<xsd:complexType name="Catalogue">
<xsd:choice maxOccurs="unbounded">
<xsd:element ref="Book" />
<xsd:element ref="Magazine" />
</xsd:choice>
</xsd:complexType>
<xsd:element name="Publication" abstract="true" type="Publication" />
<xsd:element name="Book" type="Book"/>
<xsd:element name="Magazine" type="Magazine"/>
<xsd:complexType name="Publication">
<xsd:sequence></xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Book">
<xsd:complexContent>
<xsd:extension base="Publication">
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
...
The problem here is that I have to mention all possible subtypes in the choice
element which could be a lot in a real application.
A minor issue is that, although the Catalogue
attribute has the correct type List<Publication>
it has an ugly name bookAndMagazine
.
Because of the redundant schema definition, not an option!
2.) modeling Catalogue to contain a xsd:sequence
of the parent class
<xsd:complexType name="Catalogue">
<xsd:choice maxOccurs="unbounded">
<xsd:element ref="Publication" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:complexType>
This does only work if the XML documents are formulated like <Publication xsi:type="Book"...>
. Thus, not an option!
3.) Use substitutionGroup like mentioned here http://www.xfront.com/ElementHierarchy.html
<xsd:complexType name="Catalogue">
<xsd:choice maxOccurs="unbounded">
<xsd:element ref="Publication" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:complexType>
<xsd:element name="Publication" abstract="true" type="Publication" />
<xsd:element name="Book" type="Book" substitutionGroup="Publication"/>
<xsd:element name="Magazine" type="Magazine" substitutionGroup="Publication"/>
<xsd:complexType name="Publication">
<xsd:sequence></xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Book">
<xsd:complexContent>
<xsd:extension base="Publication">
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
...
Here, the code generation is the issue because the inner element of Catalogue
is mapped to List<JaxbElement<? extends Publication>>
rather than
List<Publication>
. Hence, also this isn't an option.
How to bring all my objectives together?:
- canonical, non-redundant schema which models inheritance (such as in 2.) or 3.))
- simple and clean Java classes generated from this schema and which models inheritance (like in 2.) and partly in 1.) )
- clean XML documents (not like in 2.) )
- usage of standard JAXB and preferable not much binding metadata
And if there is no solution which matches all these objectives, which one would you prefer?