Re: Need help with any and all

Hi Brenda,

> I'm trying to develop a schema that requires element X to:
>
>     have exactly one each of child elements A, B and C in any order
>     allow other child elements from any other namespace
>
> I've been able to develop schemas that meet two of my three
> requirements but not all three. I've also been able to develop a
> schema that appears to meet all three, however validation succeeds
> when any of the required elements are omitted. If anyone else has
> done something similar, I would really appreciate any guidance you
> have to offer.

Yes, if you use xs:all to allow the elements to occur in any order
then you can't use the xs:any wildcard to allow any combination of
elements. If you use substitution groups, you can allow A, B or C in
any order, and use a wildcard, but you can't guarantee that there's
only one each of A, B and C.

So you have three options, I think:

Firstly, you could make the XML Schema enumerate the possible
combinations. This is a bit of a headache - not *too* awful with three
elements, but pretty bad:

  <xs:sequence>
    <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
    <xs:choice>
      <xs:sequence>
        <xs:element ref="A" />
        <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
        <xs:choice>
          <xs:sequence>
            <xs:element ref="B" />
            <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
            <xs:element ref="C" />
            <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
          </xs:sequence>
          <xs:sequence>
            <xs:element ref="C" />
            <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
            <xs:element ref="B" />
            <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
          </xs:sequence>
        </xs:choice>
      </xs:sequence>
      ...
    </xs:choice>

Secondly, you could use a more general content model, and then add any
additional constraints using a schema adjunct, such as Schematron. For
example:

  <xs:choice minOccurs="3" maxOccurs="unbounded">
    <xs:annotation>
      <xs:appinfo>
        <sch:rule context="X">
          <sch:assert test="count(A) = 1">
            There can only be one A element
          </sch:assert>
          <sch:assert test="count(B) = 1">
            There can only be one B element
          </sch:assert>
          <sch:assert test="count(C) = 1">
            There can only be one C element
          </sch:assert>
        </sch:rule>
      </xs:appinfo>
    </xs:annotation>
    <xs:element ref="A" />
    <xs:element ref="B" />
    <xs:element ref="C" />
    <xs:any namespace="##other" />
  </xs:choice>

Thirdly, you could make your markup language easier to represent with
an XML Schema by wrapping the elements in other namespaces within
another element. Then you can use xs:all as follows:

  <xs:all>
    <xs:element ref="A" />
    <xs:element ref="B" />
    <xs:element ref="C" />
    <xs:element name="D">
      <xs:complexType>
        <xs:sequence>
          <xs:any namespace="##other" minOccurs="0"
                                      maxOccurs="unbounded" />
        </xs:sequence>
      </xs:complexType>
    </xs:element>
  </xs:all>
  
Finally, you could make your markup language easier to represent with
an XML Schema by choosing a canonical representation in which the
order of A, B and C (and the wildcard) is specified. You could
constrain such a content model very easily:

  <xs:sequence>
    <xs:element ref="A" />
    <xs:element ref="B" />
    <xs:element ref="C" />
    <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
  </xs:sequence>

You could provide a small script, stylesheet or query to transform
from unordered versions to the canonical ordering for the purpose of
validation.
  
Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/

Received on Monday, 25 February 2002 13:26:05 UTC