Search code examples
xmlxsd

XML Choice of elements, but of same type when maxOccurs is unbounded


I am trying to define an element in an XML file using an XSD schema with a choice, which is not that hard:

    <xs:complexType abstract="true"
                    name="ESAPIObject">
        <xs:sequence>
            <xs:element name="PropertyName"
                        type="xs:string"/>
            <xs:element name="Condition"
                        minOccurs="1"
                        maxOccurs="unbounded">
...
            </xs:element>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="BeamObject">
        <xs:complexContent>
            <xs:extension base="ESAPIObject">
                <xs:sequence/>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="DoseObject">
        <xs:complexContent>
            <xs:extension base="ESAPIObject">
                <xs:sequence/>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
    <xs:complexType name="StructureObject">
        <xs:complexContent>
            <xs:extension base="ESAPIObject">
                <xs:sequence/>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:element name="Beam"
                type="BeamObject"/>
    <xs:element name="Dose"
                type="DoseObject"/>
    <xs:element name="Structure"
                type="StructureObject"/>

    <xs:group name="actualValueType">
        <xs:choice>
            <xs:element ref="Beam"/>
            <xs:element ref="Dose"/>
            <xs:element ref="Structure"/>
        </xs:choice>
    </xs:group>

    <xs:complexType name="SimpleConditionType">
        <xs:sequence>
            <xs:element name="ActualValue">
                <xs:complexType>
                    <xs:choice>
                        <xs:group ref="actualValueType" minOccurs="1" maxOccurs="unbounded"/>
                    </xs:choice>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

However the aggravating part is the fact that the choice element within ActualValue might repeat, but only if it is from the same type as previous ones? So only either Structure elements or Beam elements or Dose elements not a mixture of them, e.g.:

  <ActualValue>
   <Structure />
   <Structure />
  </ActualValue>

or

  <ActualValue>
   <Beam />
   <Beam />
  </ActualValue>

or

  <ActualValue>
   <Dose />
   <Dose />
  </ActualValue>

But not:

  <ActualValue>
   <Structure />
   <Dose />
  </ActualValue>

I can not find a way to implement this in my XSD. Any suggestions?


Solution

  • I spotted a couple of mistakes in your XSD:

    • You have defined a repeating choice instead of a choice with repeating members
    • You have a redundant <xs:choice> around your group reference
    • Your global group 'ActualValueType' should be 'ActualValueGroup' (a group is not a type, so the distinction matters)

    In order to test your xsd more easily I made ActualValue a global element declaration.

    After making those changes, I ended up with this:

        <xs:group name="actualValueGroup">
            <xs:choice>
                <xs:element ref="Beam" maxOccurs="unbounded"/>
                <xs:element ref="Dose" maxOccurs="unbounded"/>
                <xs:element ref="Structure" maxOccurs="unbounded"/>
            </xs:choice>
        </xs:group>
    
        <xs:element name="ActualValue">
            <xs:complexType>
              <xs:group ref="actualValueGroup" minOccurs="1" maxOccurs="1"/>
            </xs:complexType>
        </xs:element>
    

    ...which correctly accepts or rejects each of your examples.