Marnix
Marnix

Reputation: 6547

Xml schema extension order

If I have an extension, how can I assure that the derived elements are in front of the base class elements? The default is the other way around. I would have loved to use all, but I know that is impossible.

<xs:complexType name="BaseClass">
  <xs:sequence>
    <xs:element name="foo" type="xs:string/>
    <xs:element name="bar" type="xs:string/>
  </xs:sequence>
</xs:complexType>
<xs:complexType name="DerivedClass">
  <xs:complexContent>
    <xs:extension base="BaseClass">
      <xs:sequence>
        <!-- This makes the order foo, bar, cheese, tomato -->
        <!-- But I need cheese, tomato, foo, bar -->
        <xs:element name="cheese" type="xs:string/>
        <xs:element name="tomato" type="xs:string/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>
<xs:element name="BaseClass" type="BaseClass"/>
<xs:element name="DerivedClass" type="DerivedClass" substitutionGroup="BaseClass"/>

The xml I would like to be accepted looks something like this:

<mylist>
    <BaseClass>
     <foo>lala</foo>
     <bar>lala</bar>
    </BaseClass>
    <DerivedClass>
     <cheese>cheddar</cheese>
     <tomato>red</tomato>
     <foo>lala</foo>
     <bar>lala</bar>
    </DerivedClass>
</mylist>

At the moment I'm thinking of just copying all elements of BaseClass into DerivedClass as well, but I don't know what happens with substitutiongroups and what not.

Upvotes: 11

Views: 3798

Answers (3)

Cephalopod
Cephalopod

Reputation: 15145

The only way around this is to use groups, which can be inserted at any point in a sequence. However, with this approach you can't use substitutionGroup.

<xs:group name="BaseGroup">
  <xs:sequence>
    <xs:element name="foo" type="xs:string"/>
    <xs:element name="bar" type="xs:string"/>
  </xs:sequence>
</xs:group>
<xs:complexType name="BaseClass">
  <xs:group ref="BaseGroup"/>
</xs:complexType>
<xs:complexType name="DerivedClass">
  <xs:sequence>
    <xs:element name="cheese" type="xs:string"/>
    <xs:element name="tomato" type="xs:string"/>
    <xs:group ref="BaseGroup"/>
  </xs:sequence>
</xs:complexType>
<xs:element name="BaseClass" type="BaseClass"/>
<xs:element name="DerivedClass" type="DerivedClass"/>

Upvotes: 3

Shadi
Shadi

Reputation: 10355

I faced the same problem when validating XML that was generated by PHP.

This is how I solved it. Basically,

  1. Iterate over all the php class properties,
  2. push what is from the current class into one array,
  3. push what is from the parent class into another array.
  4. Merge the current class properties to the end of the parent class properties
  5. Generate the XML from the reordered properties array

Upvotes: 0

ColdFusion
ColdFusion

Reputation: 2531

If I have an extension, how can I assure that the derived elements are in front of the base class elements?

Unfortunately, it is impossible. When a complexType is extended, the new elements are added to the base elements as sequence. Basically, the new content model will looks as follows:

(base element model), (extension element model)

That's how the type extension in XSD works. You may wonder why? Because the extension type must comply with the base type. You cannot have anything as an extension of anything as a base.

Suppose you have a software that knows how to process elements of type A. The software may assume that actually the type A might be extended, but in any case, it must be able to find in an element supposed to be of type A everything it knows/expect from type A... and the element content inherent to type A (which is one of the most important things) must come the first!

Upvotes: 12

Related Questions