Co-occurrence constraints are interdependent conditions given on the child elements or attributes of a node, such as “if this element is present, then this attribute must be absent.” Under-implemented within W3C XML Schema, these constraints can be a workaround to the "Consistent Declaration rule,” which forbids definition of two different content models for an element at the same location in an instance document. With co-occurrence constraints, one can define a superset of the two content models and add the constraints to forbid the unwanted combinations. This is frequently useful with vocabularies (such as RDF) in which some properties can be expressed either as an attribute or an element, and in which we may want to extend our book example to accept the ISBN number and the title to be expressed as elements or attributes. The two following instance documents are then valid (with their two remaining combinations):
<book id="b0836217462" available="true"> <isbn> 0836217462 </isbn> <title lang="en"> Being a Dog Is a Full-Time Job </title> ../.. </book>
or:
<book id="b0836217462" available="true" isbn="0836217462" title="Beinga Dog Is a Full-Time Job"> .../... </book>
The obvious way is to define the book
element as a
choice between the four different valid content models (with the four
combinations of elements and attributes). However, this is forbidden
by the Consistent Declaration rule, which states that only one
content model may be used for
a given element. The workaround is to define a content model that
accepts both optional elements and attributes:
<xs:complexType> <xs:sequence> <xs:element ref="isbn" minOccurs="0"/> <xs:element ref="title" minOccurs="0"/> <xs:element ref="author" minOccurs="0" maxOccurs="unbounded"/> <xs:element ref="character" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute ref="id"/> <xs:attribute ref="available"/> <xs:attribute ref="isbn"/> <xs:attribute ref="title"/> </xs:complexType>
This definition allows instance documents with both a
title
(or isbn
) element and
attribute or instance documents without any title
or isbn
at all. We need to add co-occurrence
constraints. In a more general case, these constraints cannot be
expressed using W3C XML Schema, and we need to embed other languages
(as shown in Chapter 14) but when we think about
it,
xs:unique
,
xs:key
, and
xs:keyref
can be considered very specific
co-occurrence constraints and they can be used here. If we want to
insure that we have only one title and ISBN number, we can add a
xs:key
definition in the
book
element itself:
<xs:key name="isbn"> <xs:selector xpath="."/> <xs:field xpath="isbn|@isbn"/> </xs:key> <xs:key name="title"> <xs:selector xpath="."/> <xs:field xpath="title|@title"/> </xs:key>
These keys are evaluated in the scope of a book element and
won’t have any effect outside each book element.
They will consider the book invalid if the XPath expression in their
field
element returns either no nodes or multiple
nodes. Note that if we had used
xs:unique
instead of
xs:key
, we would still have required that
only one of the elements or attributes be present, but that would
have made the property optional. For the record, the full definition
of our book
element would then be:
<xs:element name="book"> <xs:complexType> <xs:sequence> <xs:element ref="isbn" minOccurs="0"/> <xs:element ref="title" minOccurs="0"/> <xs:element ref="author" minOccurs="0" maxOccurs="unbounded"/> <xs:element ref="character" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute ref="id"/> <xs:attribute ref="available"/> <xs:attribute ref="isbn"/> <xs:attribute ref="title"/> </xs:complexType> <xs:key name="isbn"> <xs:selector xpath="."/> <xs:field xpath="isbn|@isbn"/> </xs:key> <xs:key name="title"> <xs:selector xpath="."/> <xs:field xpath="title|@title"/> </xs:key> </xs:element>