itsmatt
itsmatt

Reputation: 31416

XML Choice without nesting

What I'm trying to accomplish is the creation of an XML schema which describes an XML file which can take one of two forms. There's a section of common elements between the two and then a small section which differs. Something like:

<Dessert>
  <Identifier> Hot Fudge Sundae </Identifier>
  <SaleDate> 2013-06-03 </SaleDate>
  <Duration> 2 </Duration>
  <Size> SuperScooper </Size>
</Dessert>

<Dessert>
  <Identifier> Dutch Apple Pie </Identifier>
  <SaleDate> 2013-06-03 </SaleDate>
  <Duration> 1 </Duration>
  <AlaMode> 1 </AlaMode>
  <IceCreamFlavor> Vanilla </IceCreamFlavor>
</Dessert>

So for the ice cream desserts there's just a Size while for the pies there's an AlaMode indicator and an IceCreamFlavor specifier.

What I want to accomplish is to use the xs:choice specifier to indicate that the Dessert XML will either have one or the other (Size or AlaMode and IceCreamFlavor) so that I can validate them.

What I've tried to do is create two types and do something like this:

and then do something like:

<xs:choice>
  <xs:element name="Sundae" type="SundaeType" />
  <xs:element name="Pie" type="PieType" />
</xs:choice>

And but the resulting XML, of course, has a layout like so:

<Dessert>
  <Identifier> Hot Fudge Sundae </Identifier>
  <SaleDate> 2013-06-03 </SaleDate>
  <Duration> 2 </Duration>
  <Sundae>
    <Size> SuperScooper </Size>
  <Sundae>
</Dessert>

Which doesn't match the existing file structure.

I can simply make the union of all possible elements and do away with the xs:choice stuff but that really doesn't convey the expectations of the format (that it is, for instance, not valid for the sundae to have an AlaMode element).

Is there any way to accomplish this? I suspect if I had just one field different I could accomplish this with the xs:choice (perhaps) and not have that additional level. Or maybe I'm just missing something here.

And yes, I realize that the layout isn't the best but it is an existing format that I can really change at this point.

Upvotes: 1

Views: 138

Answers (1)

Polly Shaw
Polly Shaw

Reputation: 3237

If you don't mind imposing an order on the elements in the source documents you can make this work using xs:sequence:

<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/XMLSchema.xsd"
    xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:complexType name="Dessert">
        <xs:sequence>
            <xs:element name="Identifier" type="xs:string"/>
            <xs:element name="SaleDate" type="xs:int"/>
            <xs:element name="Duration" type="xs:int"/>
            <xs:choice>
                <xs:element name="Size" type="xs:string"/>
                <xs:sequence>
                    <xs:element name="AlaMode" type="xs:int"/>
                    <xs:element name="IceCreamFlavor" type="xs:string"/>
                </xs:sequence>
            </xs:choice>

        </xs:sequence>
    </xs:complexType>

    <xs:element name="Dessert" type="Dessert"/>
</xs:schema>

Upvotes: 2

Related Questions