Marnix
Marnix

Reputation: 6547

Simple inheritance tree in XML schema

I believed to have understand everything in this article, but it seems that there is still some work for me.

If I have a simple inheritance tree in my classes:

A (abstract)
^
B
^
C

And I want to have a simple list of objects in my xml as followes:

<mylist>
    <B>lalala</B>
    <C>fofofo</C>
    <C>fofofo</C>
    <C>fofofo</C>
    <C>fofofo</C>
    <B>lalala</B>
</mylist>

It doesn't seem to work when I try to validate this scheme against:

<xs:schema>
    <xs:complexType name="A" abstract="true">
        <xs:element name="text" type="xs:string"/>
    </xs:complexType>
    <xs:complexType name="B">
        <xs:complexContent>
            <xs:extension base="A"/>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="C">
        <xs:complexContent>
            <xs:extension base="B"/>
        </xs:complexContent>
    </xs:complexType>

    <xs:element name="mylist>
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="A" type="A"/>
        </xs:sequence>
    </xs:element>
</xs:schema>

Remember, this is just pseudo code for the sake of short xmls without a lot of namespaces.

Why does a validator tell me (notepad++ for example) that it is still expecting an <A> and not a <B> or a <C>?

Upvotes: 0

Views: 125

Answers (1)

C. M. Sperberg-McQueen
C. M. Sperberg-McQueen

Reputation: 25054

You're getting close. But you're conflating element names with type names. Types B and C are substitutable for type A, but you haven't declared any elements named B and C at all, let alone declared them and made them substitutable for element A.

The following XML instance is valid against a corrected version of your schema:

<mylist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="Mamix.xsd">
    <A xsi:type="B"><text>lalala</text></A>
    <A xsi:type="C"><text>fofofo</text></A>
    <A xsi:type="C"><text>fofofo</text></A>
    <A xsi:type="C"><text>fofofo</text></A>
    <A xsi:type="C"><text>fofofo</text></A>
    <A xsi:type="B"><text>lalala</text></A>
</mylist>

If you want to allow elements B and C instead, declare them with appropriate types and specify that they are substitutable for element A (which must be a top-level element for this to be possible). Your schema will look like this:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:complexType name="A" abstract="true">
        <xs:sequence>
            <xs:element name="text" type="xs:string"/>
        </xs:sequence>        
    </xs:complexType>

    <xs:complexType name="B">
        <xs:complexContent>
            <xs:extension base="A"/>
        </xs:complexContent>
    </xs:complexType>

    <xs:complexType name="C">
        <xs:complexContent>
            <xs:extension base="B"/>
        </xs:complexContent>
    </xs:complexType>

    <xs:element name="A" type="A"/>
    <xs:element name="B" type="B" substitutionGroup="A"/>
    <xs:element name="C" type="C" substitutionGroup="A"/>

    <xs:element name="mylist">
        <xs:complexType>
            <xs:sequence maxOccurs="unbounded">
                <xs:element ref="A"/>
            </xs:sequence>            
        </xs:complexType>
    </xs:element>

</xs:schema>

Against this schema, the following instance (modified from your original XML by adding the 'text' element your declaration for 'A' requires) is valid:

<mylist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="Mamix.xsd">
    <B><text>lalala</text></B>
    <C><text>fofofo</text></C>
    <C><text>fofofo</text></C>
    <C><text>fofofo</text></C>
    <C><text>fofofo</text></C>
    <B><text>lalala</text></B>
</mylist>

Upvotes: 1

Related Questions