XML 1.0 provided the ability to declare an element that could
contain parsed character data (#PCDATA
) and unlimited occurrences of
elements drawn from a provided list. Schemas provide the same
functionality plus the ability to control the number and sequence in
which elements appear within character data.
The mixed
attribute of the
complexType
element controls whether character data may appear
within the body of the element with which it is associated. To
illustrate this concept, Example
17-9 gives us a new schema that will be used to validate
form-letter documents.
Example 17-9. formletter.xsd
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema"> <xs:element name="letter"> <xs:complexType mixed="true"/> </xs:element> </xs:schema>
This schema seems to declare a single element called letter
that may contain character data and
nothing else. But attempting to validate the following document
produces an error, as shown in Example 17-10.
Example 17-10. formletterdoc.xml
<letter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="formletter.xsd">Hello!</letter>
The following error is generated:
The content of element type "letter" must match "EMPTY".
This is because there's no complex content for the letter
element. Setting mixed
to true
is not the same as declaring an
element that may contain a string. The character data may only
appear in relation to other complex content, which leads to the
subject of relative element positioning.
You have already seen the xs:sequence
element, which dictates that the elements it contains
must appear in exactly the same order in which they appear within
the sequence element. In addition to xs:sequence
, schemas also provide the
xs:choice
and xs:all
elements to control the order in which elements may appear. These
elements may be nested to create sophisticated element
structures.
Expanding the form-letter example, a sequence adds support for
various letter components to the formletter.xsd
schema:
<xs:element name="letter"> <xs:complexType mixed="true"> <xs:sequence> <xs:element name="greeting"/> <xs:element name="body"/> <xs:element name="closing"/> </xs:sequence> </xs:complexType> </xs:element>
Now, thanks to the xs:sequence
element, a letter must include
a greeting
element, a body
element, and a closing
element, in that order. But, in
some cases, what is desired is that one and only one element appear
from a collection of possibilities. The xs:choice
element supports this. For
example, if the greeting
element
needed to be restricted to contain only one salutation out of a
permissible list, it could be declared to do so using xs:choice
:
<xs:element name="greeting"> <xs:complexType mixed="true"> <xs:choice> <xs:element name="hello"/> <xs:element name="hi"/> <xs:element name="dear"/> </xs:choice> </xs:complexType> </xs:element>
Now one of the permitted salutations must appear in the
greeting
element for the letter
to be considered valid.
The remaining element-order enforcement construct is the
xs:all
element. Unlike the
xs:sequence
and xs:choice
elements, the xs:all
element must appear at the top of
the content model and can only contain elements that are optional or
appear only once. The xs:all
construct tells the schema processor that each of the contained
elements must appear once in the target document, but can appear in
any order. This could be applied in the form letter example. If the
form letter had certain elements that had to appear in the body
element, but not in any particular
order, xs:all
could be used to
control their appearance:
<xs:element name="body"> <xs:complexType mixed="true"> <xs:all> <xs:element name="item"/> <xs:element name="price"/> <xs:element name="arrivalDate"/> </xs:all> </xs:complexType> </xs:element>
This would allow the letter author to mix these elements into
the narrative without being restricted to any particular order.
Also, it would prevent the author from inserting multiple references
to the same value by accident. A valid document instance, including
the new body
content, might look
like Example
17-11.
Just as the xs:attributeGroup
element allows commonly used attributes to be grouped
together and referenced as a unit, the xs:group
element allows sequences, choices, and model groups
of individual element declarations to be grouped together and given
a unique name. These groups can then be included in another
element-content model using an xs:group
element with the ref
attribute set to the same value as the
name
attribute of the source
group. When you do this, any occurrence constraints have to be
specified on the reference to the group rather than on the
definition of the group.