1
votes

I wish to define an XSD (v1.0 based) that enforces the following rules...

I have a parent1 element, which can have the following child elements child1, child2, and child3.

  • parent1 can have 0-1 of child1
  • parent1 can have 0-1 of child2
  • parent1 can have 0 - unbounded of child3

The order of the items is not important. E.g.

<parent1>
  <child3/>
  <child1/>
  <child2/>
  <child3/>
  <child3/>
</parent1>

I've gotten close, but no cigar. The closest I can get is the enforcing of the min and max occurs, but the order is enforced.

<xsd:element name="parent1" minOccurs="0" maxOccurs="unbounded">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element name="child1" minOccurs="0" maxOccurs="1"/>
      <xsd:element name="child2" minOccurs="0" maxOccurs="1" />
      <xsd:element name="child3" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

I've tried using all instead of sequence, but that limits maxOccurs to 1 for the child elements. I've also tried using choice with a maxOccurs to replace sequence, but that doesn't limit how many child1 or child2 elements you can have beneath parent1.

Edit: this is for XSD v1.0

I've found a solution that works for XSD 1.1, but when you see how well supported it is in the likes of Eclipse, I'll try and stick with 1.0.

3

3 Answers

1
votes

As Hantin says, this is combinatorially messy in XSD 1.0.

In XSD 1.1 you can have a maxOccurs attribute on the particles of an xs:all model group, so your problem is solved. XSD 1.1 is currently implemented in Saxon and Xerces.

1
votes

It's not particularly hard, though as Michael Kay has pointed out, it's messy and disappointingly verbose. Translating Jeffrey Hantin's example into DTD notation for conciseness and using c1, c2, and c3 (again for brevity) for the element names, the solution is

(c3*, ((c1, c3*, (c2, c3*)?) | (c2, c3*, (c1, c3*)?))?)

If the sequence of child elements conveys information, then it's important to all this flexibility of ordering, of course. If the sequence does not convey any information, then there is no need to allow the flexibility and the OP's original solution should usually be preferred.

0
votes

To do this in XML Schema 1.0 you end up having to "unroll" the would-be xs:all particle into a choice-of-sequences tree (where each branch of each choice has a unique non-optional first element) giving you something like this:

EDIT: corrected my perception of the requirements and greatly reduced verbosity as a result. Some optimizations to further reduce verbosity were also performed: choices containing an empty branch had the empty branch converted to minOccurs=0 on the choice, and if that transformation left a choice with only one branch, the choice itself was elided and the minOccurs="0" transferred to its sole child.

<xs:sequence>
  <xs:element name="nationality" minOccurs="0" maxOccurs="unbounded" />
  <xs:choice minOccurs="0">
    <xs:sequence>
      <xs:element name="name" />
      <xs:element name="nationality" minOccurs="0" maxOccurs="unbounded" />
      <xs:sequence minOccurs="0">
        <xs:element name="email" />
        <xs:element name="nationality" minOccurs="0" maxOccurs="unbounded" />
      </xs:sequence>
    </xs:sequence>
    <xs:sequence>
      <xs:element name="email">
      <xs:element name="nationality" minOccurs="0" maxOccurs="unbounded" />
      <xs:sequence minOccurs="0">
        <xs:element name="name" />
        <xs:element name="nationality" minOccurs="0" maxOccurs="unbounded" />
      </xs:sequence>
    </xs:sequence>
  </xs:choice>
</xs:sequence>