Search code examples
xmlxsdxml-validationxsd-1.0

XML validation: Concurrent unordered and occurrence requirements in XSD


In XML Schema (XSD 1.0), I have following requirements for four elements:

  1. element1 will appear always first, with minOccurs = 0 and maxOccurs = 1
  2. element2 will appear with minOccurs = 0 and maxOccurs = 1
  3. element3 will appear with minOccurs = 0 and maxOccurs = unbounded
  4. element2 and element3 will appear in any order (after element1 and before element4)
  5. element4 will appear always in the end with minOccurs = 0 and maxOccurs = unbounded
  6. All of these elements are children of a parent_element, and as all of them have minOccurs = 0, but at least 1 of them should be present in the parent element.

I have created a scheme which fulfills all requirements except #2 and #6. In my schema element2 and element3 can appear in any order, but I am unable to restrict element2 to occur only once. Also, I am unable to make sure at least 1 element is present in the parent_element.

Review my schema below and suggest the updates to fulfill all of the above requirements.

<xs:element name="parent_element">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="element1" type="type1" minOccurs="0" maxOccurs="1" />
            <xs:choice minOccurs="0" maxOccurs="unbounded" >
                <xs:element name="element2" type="type1" />
                <xs:element name="element3" type="type1" />
            </xs:choice>
            <xs:element name="element4" type="type2" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

In order to fulfill requirement #2 I tried a trick of using maxOccurs="1" with element2 (inside choice) but it did not work and element2 was still able to be repeated more than once in any order with element3.

<xs:element name="parent_element">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="element1" type="type1" minOccurs="0" maxOccurs="1" />
            <xs:choice minOccurs="0" maxOccurs="unbounded" >
                <xs:element name="element2" type="type1" maxOccurs="1" />
                <xs:element name="element3" type="type1" />
            </xs:choice>
            <xs:element name="element4" type="type2" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

Solution

  • Requirements #4 and #6 preclude use of XSD 1.0.

    XSD 1.1 can meet these requirements via xs: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"
               elementFormDefault="qualified"
               vc:minVersion="1.1">
        <xs:element name="parent_element">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="element1" minOccurs="0" maxOccurs="1" />
              <xs:choice minOccurs="0" maxOccurs="unbounded" >
                <xs:element name="element2" />
                <xs:element name="element3" />
              </xs:choice>
              <xs:element name="element4" minOccurs="0" maxOccurs="unbounded" />
            </xs:sequence>
            <xs:assert test="count(element2) &lt; 2 
                              and (element1 or element2 or element3 or element4)"/>
          </xs:complexType>
        </xs:element>
    </xs:schema>