10

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.

Marnix
  • 6,384
  • 4
  • 43
  • 78

3 Answers3

10

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!

ColdFusion
  • 2,381
  • 13
  • 14
  • That is too bad, since our XmlWriter is writing it in the opposite direction for a long time. I cannot alter the XML's anymore. I have decided to flatten everything out and just rewrite every case from A to Z without extensions. – Marnix Sep 17 '13 at 14:21
  • Also a shame. In my case this prevented factoring of common elements (the alternative would have been updating many existing documents). – dhardy Aug 22 '14 at 16:16
3

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"/>
Cephalopod
  • 14,632
  • 7
  • 51
  • 70
0

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
Shadi
  • 9,742
  • 4
  • 43
  • 65