Search code examples
xmlinheritancexsdabstractextend

Is it possible to instantiate a double-extended complexType?


Consider the following scenario:

I want to save elements and their attributes in a database, these elements extend from a common but abstract supertype called "PersistentElement". Now some of these elements all have a particular attribute, e.g. they all have a name, and all of these elements again share a common superelement named "NamedElement", which again is abstract. That leads to a schema/XSD looking like this:

<xs:element name="Database">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="elements" type="PersistentElement" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

<xs:complexType name="PersistentElement" abstract="true">
    <xs:attribute name="id" type="xs:ID"/>
</xs:complexType>

<xs:complexType name="NamedElement" abstract="true">
    <xs:complexContent>
        <xs:extension base="PersistentElement">
             <xs:attribute name="name" type="xs:string"/>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

<xs:complexType name="ElementWithName">
    <xs:complexContent>
        <xs:extension base="NamedElement">
            <xs:element name="somethingElse" type="xs:string"/>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

Now my question: is this even possible in XML? The most obvious fix for that would be to make one of the abstract elements a xs:choice-type of element, but just out of curiousity, and because I am still learning, I would like to know if a double extended abstract element is possible. The problem I face is, that I can't (or more exact do not know how to) instantiate a such a element in the corresponding XML file. What I want is:

<Database>
    <elements xsi:type="ElementWithName" id = "E1" name="testElement1" >
        <somethingElse>bla</somethingElse>
    </elements>
    <elements xsi:type="ElementWithName" id = "E2" name="testElement2" >
        <somethingElse>blub</somethingElse>
    </elements> 
</Database>

But this gives me an error when I try to validate this,

Cvc-elt.4.2: Cannot Resolve 'ElementWithName' To A Type Definition For Element 'elements'.. Line '13', Column '66'.
Cvc-type.2: The Type Definition Cannot Be Abstract For Element Elements.. Line '13', Column '66'.
Cvc-complex-type.3.2.2: Attribute 'name' Is Not Allowed To Appear In Element 'elements'.. Line '13', Column '66'.
Cvc-complex-type.2.1: Element 'elements' Must Have No Character Or Element Information Item [children], Because The Type's Content Type Is Empty.. Line '16', Column '16'.

Solution

  • Yes, you can extend an already extended type.

    The error message that Xerces gives for your XSD is:

    s4s-elt-invalid-content.1: The content of 'ElementWithName' is invalid. Element 'element' is invalid, misplaced, or occurs too often.

    Wrapping xs:element/@name="somethingElse" in a xs:sequence resolves this error.

    Here is the complete, corrected XSD:

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    
      <xs:element name="Database">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="elements" type="PersistentElement" minOccurs="0"
                        maxOccurs="unbounded" />
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    
      <xs:complexType name="PersistentElement" abstract="true">
        <xs:attribute name="id" type="xs:ID"/>
      </xs:complexType>
    
      <xs:complexType name="NamedElement" abstract="true">
        <xs:complexContent>
          <xs:extension base="PersistentElement">
            <xs:attribute name="name" type="xs:string"/>
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
    
      <xs:complexType name="ElementWithName">
        <xs:complexContent>
          <xs:extension base="NamedElement">
            <xs:sequence>
              <xs:element name="somethingElse" type="xs:string"/>
            </xs:sequence>
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
    </xs:schema>
    

    Here is a valid XML document per the above XSD:

    <?xml version="1.0" encoding="UTF-8"?>
    <Database xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:noNamespaceSchemaLocation="Database.xsd">
        <elements xsi:type="ElementWithName" id = "E1" name="testElement1" >
            <somethingElse>bla</somethingElse>
        </elements>
        <elements xsi:type="ElementWithName" id = "E2" name="testElement2" >
            <somethingElse>blub</somethingElse>
        </elements> 
    </Database>