views:

229

answers:

1

I know about all and choice, but they don't account for a case where I do want some elements to be able to occur more than once, such as:

<Root>
    <ThingA/>
    <ThingB/>
    <ThingC/>
    <ThingC/>
    <ThingC/>
</Root>

I could use sequence, but I'd prefer to allow these children to be in any order. I could use any, but then I couldn't have more than one ThingC. I could use choice, but then I couldn't limit ThingA and ThingB to 0 or 1.

I think I may have read somewhere that this was either difficult or impossible in XSD, but might be possible with RELAX NG. I don't remember where I read that, unfortunately.

Thanks for any help!

+4  A: 

That's right: you can't do what you want to do in XML Schema, but you can in RELAX NG with:

<element name="Root">
  <interleave>
    <element name="ThingA"><empty /></element>
    <element name="ThingB"><empty /></element>
    <oneOrMore><element name="ThingC"><empty /></element></oneOrMore>
  </interleave>
</element>

Your options in XML Schema are:

  • add a preprocessing step that normalises your input XML into a particular order, and then use <xs:sequence>
  • use <xs:choice>, and add extra validation (for example using Schematron) to check that there's not more than one <ThingA> or <ThingB>
  • decide to fix the order of the elements in your markup language

It turns out that the third is usually the best option; there's usually not much cost for generators of XML to output elements in a particular order, and not only does it help validation but it also aids consumption of the XML if the order can be known in advance.

JeniT
Thank you for the excellent answer, I really appreciate it!
Avi Flax