maphongba008
maphongba008

Reputation: 2353

minOccurs and maxOccurs on elements inside xsd:choice

I have a root element <a> and its children <b>, <c>, <d>

Here's what I need:

For example:

<a>
    <c />
    <b />
    <c />
    <d /> 
</a>

And here is my XSD:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified">
  <xs:element name="a">
    <xs:complexType>
      <xs:choice>
        <xs:element name="b" />
        <xs:element name="c" minOccurs="1" maxOccurs="unbounded"/>
        <xs:element name="d" minOccurs="0" maxOccurs="1"/>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

But the minOccurs and maxOccurs in xs:element may not work. When I run the example, I got an error:

Element <b> is not allowed at this location under element <a>.

How can I fix this?

Upvotes: 3

Views: 2177

Answers (1)

kjhughes
kjhughes

Reputation: 111491

Here's what your XSD says: Within a you can choose one of the following options:

  1. A single b element.
  2. One or more c elements.
  3. Zero or one d elements.

Your XML chooses option #2. It doesn't get a second choice, and when the parser encounters the b element, it correctly reports the violation.

You might think you could fix this by granting multiple choices:

  <xs:choice maxOccurs="unbounded">

This would now say: Within a you can repeatedly choose one of the following options:

  1. A single b element.
  2. One or more c elements.
  3. Zero or one d elements.

Your XML would now choose option #2, then option #1, then option #2, then option #3, then declare that your XML is valid. Success?

No, not if, for example, you wish to ensure only one b element child because the choice itself is repeated, and option #1 can be repeatedly selected, each time allowing a single b element, but in aggregate, effectively allowing multiple b elements.

For this reason, xsd:choice and, in fact, XSD 1.0 in general cannot be used to represent your constraint.

Your options? Check this constraint in code outside of XSD, or use XSD 1.1's xsd:assert:

XSD 1.1 Solution

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
           vc:minVersion="1.1">
  <xs:element name="a">
    <xs:complexType>
      <xs:choice maxOccurs="unbounded">
        <xs:element name="b" />
        <xs:element name="c"/>
        <xs:element name="d"/>
      </xs:choice>
      <xs:assert test="count(b) = 1 and count(c) > 1 and count(d) >= 0"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

Upvotes: 3

Related Questions