2

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.

Community
  • 1
  • 1
Roadkillnz
  • 773
  • 1
  • 6
  • 14

3 Answers3

1

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.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • 1
    Thankyou, that's good to know. The problem we're facing is we plan to use Eclipse as the development environment for defining the XML that is bound to that XSD. The XML + XSD thing is a small part of a bigger picture. It's a shame that Eclipse or Web Tools Platform still doesn't support 1.1. Perhaps there's a 3rd party plugin that could come to our rescue. – Roadkillnz Sep 18 '12 at 20:28
1

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.

C. M. Sperberg-McQueen
  • 24,596
  • 5
  • 38
  • 65
  • Thankyou for your translation of Hantin's solution in relation to my example. It seems quite amazing that XSD 1.0 missed what I thought to be an obvious use-case for defining XML validation rules. But then again, it's always easy to be a critic of something - designing something to be flexible, and cover all cases can be a different story. – Roadkillnz Sep 18 '12 at 20:25
  • I guess it depends on what you mean by "missed". The content model you say you want can be expressed in XSD, as indeed in DTDs; doesn't seem to me that it was missed at all. – C. M. Sperberg-McQueen Sep 18 '12 at 21:57
  • @C.M.Sperberg-McQueen It wasn't "missed" as such, but rather a *deliberate choice* was made to omit any concise syntax for a model group in which order of elements conveys no information, at least one element has a minimum cardinality of 1 and at least one element has a maximum cardinality greater than 1, perhaps because of the combinatorial explosion that results when building a finite automaton to match the model group. – Jeffrey Hantin Sep 18 '12 at 22:39
0

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>
Jeffrey Hantin
  • 35,734
  • 7
  • 75
  • 94
  • Thankyou for your answer. Given how verbose the solution is, we'll have to look at using v1.1 afterall. My example was a fairly small contrived example, simply to get an idea of the 1.0 solution.In actuality, we'll have more than 3 child element types. And this is only 1 area of the XSD. – Roadkillnz Sep 18 '12 at 20:20
  • @Roadkillnz Now that I have more functioning brain cells, I came up with a much shorter solution. It's still kind of verbose though. – Jeffrey Hantin Sep 18 '12 at 22:57