views:

119

answers:

1

Taking the W3C vehicle XSD as an example:

<schema xmlns="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://cars.example.com/schema"
           xmlns:target="http://cars.example.com/schema"&gt;

  <complexType name="Vehicle" abstract="true"/>

  <complexType name="Car">
    <complexContent>
      <extension base="target:Vehicle"/>
      ...
    </complexContent>
  </complexType>

  <complexType name="Plane">
    <complexContent>
      <extension base="target:Vehicle"/>
      <sequence>
        <element name="wingspan" type="integer"/>
      </sequence>
    </complexContent>
  </complexType>      
</schema>

, and the following definition of 'meansOfTravel':

<complexType name="MeansOfTravel">
  <complexContent>
    <sequence>        
      <element name="transport" type="target:Vehicle"/>        
    </sequence>
  </complexContent>
</complexType>

<element name="meansOfTravel" type="target:MeansOfTravel"/>

With this definition you need to specify the type of your instance using xsi:type, like this:

<meansOfTravel>
  <transport xsi:type="Plane">
     <wingspan>3</wingspan>
  </transport>
</meansOfTravel>

I would just like to acheive a 'name of type' - 'name of element' mapping so that this could be replaced with just

<meansOfTravel>
  <plane>
    <wingspan>3</wingspan>
  </plane>
</meansOfTravel>

The only way I could do this until now is by making it explicit:

<complexType name="MeansOfTravel">
  <sequence>        
    <choice>
      <element name="plane" type="target:Plane"/>
      <element name="car" type="target:Car"/>         
    </choice>
  </sequence>
</complexType>

<element name="meansOfTravel" type="target:MeansOfTravel"/>

But this means that I have to list all possible sub-types in the 'MeansOfTravel' complex type. Is there no way of making the XML parser assume that you mean a 'Plane' if you call the element 'plane'? Or do I have to make the choice explicit? I would just like to keep my design DRY - if you have any other suggestions (like groups or so) - i am all ears.

A: 

There is a common design pattern around this, you can use sub-types (as you are already doing), and elements in a substitution group. Elements in the substitution group have to be of a sub-type of the element they are substituted for.

Unfortuntaly, substitution group elements need to be defined as global elements. So you would have this:

<complexType name="MeansOfTravel">
  <complexContent>
    <sequence>        
      <element ref="transport"/>
    </sequence>
  </complexContent>
</complexType>

<element name="transport" type="target:Vehicle"/>
<element name="plane" type="target:Plane" substitutionGroup="target:transport"/>

Then, in your XML document you can use:

<meansOfTravel>
    <plane>...</plane>
</meansOfTravel>

More info on substitution groups here. And no, unfortunately the parser cannot guess this, so you still have to list the elements :( There is one advantage over a choice though: the schema can be extended externally, by importing it, without modifying it. The choice could not be extended.

xcut
Thank you, this looks neat. Are there any other benefits of using this over choice, except from the extension argument? I'm asking since it looks quite busy, and I wonder if choice would be a more logical choice (no pun intended) considering readability.
disown
If the entire schema is under your control, I would go for a choice. Amongst other things, it makes classes generated using data-binding easier to read, and avoids introducing all these global elements.
xcut
Ok. Choice it is. Thanks again.
disown