adickinson
adickinson

Reputation: 543

Declare collection of varying types in XSD

I have an API that returns an XML set of objects, these objects are guaranteed to be representable by an abstract class, however they are not directly accessible as a list since they take the following form:

<Response Timestamp="2019-02-06T13:16:32">
    <TypeA [xml attributes]...>
        ...
    </TypeA>
    <TypeB ...>
        ...
    </TypeB>
    ... (Different repeating elements)
</Response>

Due to company practices I am to write the model for this feed using an XSD, which is parsed by JaxB to generate the source files. However, short of individually declaring the Types as possible elements of the collection (which I do not want to do for obvious reasons), I do not know how to approach this and get the child elements of the response as one single collection.

XSD for the response.

<xs:complexType name="Response">
    <xs:sequence>
        <xs:element name="Types" type="model:AbstractType" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>

Example element type

public class TypeA extends AbstractType
{
    //Generated source
}

How do I designate in the XSD that any TypeX object, extending AbstractType, should go in to the Types collection from the response?

Happy to provide any necessary further information, as long as it is not something I am not allowed to share.

Saw this related question however it accepted any element, and the restriction was based on name, whereas for this I would ideally like to validate that the elements collected are valid TypeX objects.

Upvotes: 0

Views: 79

Answers (1)

cdan
cdan

Reputation: 3576

Assuming you have defined each TypeX as AbstractType extension in the XSD:

<xsd:complexType name="TypeX">
        <xsd:complexContent>
            <xsd:extension base="AbstractType">
                ...
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

Then you can do:

1) XSD choice, if you really want to use different XML element names for each TypeX (not recommended because requires to modify the Response type whenever you add a new AbstractType subtype):

<xs:complexType name="Response">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="typeA" type="model:TypeA" />
        <xs:element name="typeB" type="model:TypeB" />
    </xs:sequence>
</xs:complexType>

2) XML polymorphism (close to what you suggest), more generic although changes the XML form:

<xs:complexType name="Response">
    <xs:sequence>
        <xs:element name="something" type="model:AbstractType" minOccurs="0" maxOccurs="unbounded" />
    </xs:sequence>
</xs:complexType>

(Replace 'something' with some meaningful name depending on what AbstractType represents actually.)

The xml would look like this:

<Response Timestamp="2019-02-06T13:16:32" xmlns="...">
    <something xsi:type="TypeA" [xml attributes]...>
        ...
    </something>
    <something xsi:type="TypeB" ...>
        ...
    </something>
    ... (Different repeating elements)
</Response>

In both cases, I recommend you use JAXB RI extension for simpler/better binding mode (§ 3.1.6), or equivalent extension, that simplifies the generated code and convert generated fields to plural form when necessary.

Then the generated code in Response class (notice the plural form): List<AbstractType> somethings; .

Upvotes: 1

Related Questions