The
xs:include
and
xs:redefine
elements are features which provide a safe way to include
“pieces” of schemas. Their
processing model is designed to provide a result that is a coherent
schema. However, the price for this safety is a certain rigidity:
only full schema documents can be included and the insertion can
only occur at a global level in a schema. (It is not possible, for
instance, to pick a couple of definitions in a schema without
including the others.) These rules mean that these features cannot be
used to include local elements, such as annotations or commonly used
facets. Let’s imagine, for instance, that we want to
require that all our dates and related datatypes specify a time zone,
and that we have worked very hard to define a generic pattern to use
to enforce this constraint. This can be something such as:
<xs:pattern value=".+(Z|[+-].{5})"/>
We could derive user-defined datatypes for each of the eight
primitive times—which can have a time zone using this
pattern—and ask to our schema designers to use only these
datatypes in their schemas. However, we may prefer to give them this
pattern as a tool, which they can use in their schemas by reference
instead of copying it (we may want to keep the possibility of
modifying the pattern without having to update all the schemas). In
this case,
xs:include
and
xs:redefine
cannot be used, and
we must consider using one of the generic XML inclusion methods,
which are external parsed entities and XInclude.
External parsed entities are one of the SGML features inherited by XML though its DTD. As the name indicates, these are entities (i.e., something you need to declare in the DTD and can reference later on in your document) that are external (i.e., their replacement value is read from an external file when they are referenced) and parsed (i.e., their content is parsed and merged into the infoset of the including document).
To use external parsed entities, we will create an XML document with the pattern we want to include:
<?xml version="1.0"?> <xs:pattern value=".+(Z|[+-].{5})" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
Note that including a namespace declaration in this file (which will be used as an external parsed entity) is not strictly mandatory, if we are sure that this entity will always be used in documents in which the namespace has already been defined with the same prefix. However, even in this case, the redefinition of the namespace is allowed though it will have no effect. Defining it will guarantee that if another prefix has been used in the included document, the snippet that we include will still be understood as belonging to the W3C XML Schema namespace. To use this entity, it must be declared in the internal or external DTD of our schema and referred to in our derivations:
<?xml version="1.0"?> <!DOCTYPE xs:schema[ <!ENTITY TZ-pattern SYSTEM "pattern.ent"> ]> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="myDate"> <xs:restriction base="xs:date"> &TZ-pattern; </xs:restriction> </xs:simpleType> <xs:element name="myDate" type="myDate"/> </xs:schema>
The interesting thing here is we have a finer granularity than we could have achieved using the W3C XML Schema inclusion mechanisms, which manipulate only global components. The price for using a general purpose inclusion mechanism such as external parsed entities (or XInclude, discussed in the next section) is that this mechanism doesn’t implement any of the semantics of W3C XML Schema and doesn’t allow any redefinition. Beyond this simple example, other DTD features, such as internal parsed entities, and even parameter entities can be used in conjunction with W3C XML Schema to produce innovative combinations!
Currently a W3C Candidate
Recommendation, XInclude is a XML application that relies on
XPointer. XInclude will eventually
replace external parsed entities and can be used in a similar way;
the main difference is that a XInclude reference
doesn’t need to be declared prior to its use and can
include a fragment of a XML document. The same example can then be
implemented using XInclude, taking advantage of its feature to fetch
our pattern by its id
even if it is defined within
a more complete schema such as:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="date"> <xs:restriction base="xs:date"> <xs:pattern value=".+(Z|[+-].{5})" id="TZ-pattern"/> </xs:restriction> </xs:simpleType> <xs:element name="myDate" type="myDate"/> </xs:schema>
Now that the id
attribute of the
xs:pattern
element is defined, we can use the
XPointer “bare names” syntax, which
allows us to use the value of an id
as a fragment
identifier. In our case, the XPointer reference to our
xs:pattern
definition is thus
pattern.xsd#TZ-pattern
. We can write:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xi="http://www.w3.org/2001/XInclude"> <xs:simpleType name="myDateTime"> <xs:restriction base="xs:dateTime"> <xi:include href="pattern.xsd#TZ-pattern" parse="xml"/> </xs:restriction> </xs:simpleType> <xs:element name="myDate" type="myDateTime"/> </xs:schema>
Note that XInclude is still a work in progress, and that this syntax may change before XInclude reaches the status of W3C Recommendation. Also note that a parser implementing XInclude should be used to read such a schema.