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/