ajcaruana
ajcaruana

Reputation: 505

XML/XSD - How to make an element appear only once in a <xs:choice> that can appear multiple times?

I have an XML Schema that defines a complexType as follows:

<xs:complexType name="CompType">
    <xs:sequence>
        <xs:element name="A" type="TypeA" minOccurs="0" maxOccurs="1"/>
        <xs:choice minOccurs="1" maxOccurs="12">
            <xs:element name="B" type="TypeB"/>
            <xs:element name="C" type="TypeC"/>
            <xs:element name="D" type="TypeD"/>
        </xs:choice>
    </xs:sequence>
</xs:complexType>

I need it to validate an XML element which can have a max of 12 "normal" sub-elements (normal = TypeB, TypeC or TypeD), but may have an additional "special" sub-element of TypeA.

As it is it works, but I do not want to restrict the "special" sub-element to be always the first. In other words, I want to be able to do something like the below, with an added restriction that there can only be a single TypeA sub-element, and no more than 12 "normal" sub-elements.

<xs:complexType name="CompType">
    <xs:sequence>
        <xs:choice minOccurs="1" maxOccurs="13">
            <xs:element name="A" type="TypeA"/>
            <xs:element name="B" type="TypeB"/>
            <xs:element name="C" type="TypeC"/>
            <xs:element name="D" type="TypeD"/>
        </xs:choice>
    </xs:sequence>
</xs:complexType>

Is this at all possible? If yes, can someone indicate how or, at least, point me in the right direction?

Upvotes: 1

Views: 2764

Answers (1)

kjhughes
kjhughes

Reputation: 111726

The Unique Particle Attribution (UPA) constraint will thwart any clever attempts at achieving this goal for XSD 1.0.

Even the case where you want 0 or more B, C, or D's and only 0 or 1 A's in arbitrary order cannot be done. Consider:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           version="1.0">

  <xs:element name="X" type="CompType"/>

  <xs:complexType name="CompType">
      <xs:sequence>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="B"/>
          <xs:element name="C"/>
          <xs:element name="D"/>
        </xs:choice>
        <xs:element name="A" minOccurs="0"/>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="B"/>
          <xs:element name="C"/>
          <xs:element name="D"/>
        </xs:choice>
      </xs:sequence>
  </xs:complexType>
</xs:schema>

Validation would require look ahead of more than one tag and thus would violate the UPA. Xerces would express its unhappiness:

cos-nonambig: B and B (or elements from their substitution group) violate "Unique Particle Attribution". During validation against this schema, ambiguity would be created for those two particles.

The problem remains in the maxOccurs=12 scenario unless you want to get crazy and enumerate all possibilities.

If you can use XSD 1.1, you may be able to use its xs:assert facilities. (Untested:)

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           version="1.1">

  <xs:element name="X" type="CompType"/>

  <xs:complexType name="CompType">
    <xs:choice minOccurs="0" maxOccurs="unbounded">
      <xs:element name="A"/>
      <xs:element name="B"/>
      <xs:element name="C"/>
      <xs:element name="D"/>
    </xs:choice>
    <xs:assert test="(count(./A) le 1) and (count(./A) + count(./B) + count(./C) + count(./D) le 13)"/>
  </xs:complexType>
</xs:schema>

Upvotes: 1

Related Questions