Other Alternatives

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.