home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Book HomeXML SchemaSearch this book

Chapter 8. Creating Building Blocks

We have already seen most of the basic building blocks: elements, attributes, simple and complex types, element and attribute groups. In this chapter, we will see how we can reuse these building blocks between schemas. In doing so, we will see how schemas can be included and redefined to create schema libraries.

8.1. Schema Inclusion

The first and most straightforward way to build schema libraries is through inclusion, a feature similar to the inclusion in traditional programming languages, such as C. Compared to a "physical" inclusion, such as the result of expanding an external entity reference, or using XInclude (described in Section 8.3.2, "XInclude", later in this chapter), schema inclusion is a "logical" inclusion, which can control the semantic of the inclusion. Schema inclusion may also be seen as a specific form of schema redefinition (seen in the next section). Note that a schema inclusion or redefinition is restricted to the definition of a single namespace (or lack of namespace) and that another mechanism (schema import), which is discussed in Chapter 10, "Controlling Namespaces", must be used to import definitions for other namespaces.

Schema inclusions must be top-level elements, children of the xs:schema element. Their effect is to include all the top-level declarations of the included schema (which doesn't need to be a complete schema). The included top-level elements are then considered top-level elements of the resulting schema. There are no priority or precedence rules and the conflicts that may arise if a local definition is duplicated in both schemas are considered errors. We could use this feature to locate all our simple type definitions in a separate schema. This sub-schema would look like:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:simpleType name="string255">
    <xs:restriction base="xs:token">
      <xs:maxLength value="255"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="string32">
    <xs:restriction base="xs:token">
      <xs:maxLength value="32"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="isbn">
    <xs:restriction base="xs:NMTOKEN">
      <xs:totalDigits value="10"/>
      <xs:pattern value="[0-9]{9}[0-9X]"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="bookID">
    <xs:restriction base="xs:ID">
      <xs:pattern value="b[0-9]{9}[0-9X]"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="supportedLanguages">
    <xs:restriction base="xs:language">
      <xs:enumeration value="en"/>
      <xs:enumeration value="es"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="date">
    <xs:restriction base="xs:date">
      <xs:pattern value="[^:Z]*"/>
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

And then include it in our main schema using:

<xs:include schemaLocation="simple-types.xsd"/>

In this example, there is a one-way dependency: the simple types are defined in simple-types.xsd and used in our main schema. The included schema is not very useful by itself. It has no element declaration, and cannot be used as a standalone schema, since it couldn't validate any instance document. However, this is a complete schema that doesn't contain any reference except to predefined simple types. This completeness of the included schema is not a requirement, as we see if we do the same for our complex type definitions:

<?xml version="1.0"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="elementWithID">
    <xs:attribute ref="id"/>
  </xs:complexType>
  <xs:complexType name="bookTmp">
    <xs:complexContent>
      <xs:extension base="elementWithID">
        <xs:sequence>
          <xs:element ref="isbn"/>
          <xs:element ref="title"/> 
          <xs:element ref="author" minOccurs="0"
            maxOccurs="unbounded"/> 
          <xs:element ref="character" minOccurs="0"
            maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute ref="available"/>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  <xs:complexType name="personType">
    <xs:complexContent>
      <xs:extension base="elementWithID">
        <xs:sequence>
          <xs:element ref="name"/>
          <xs:element ref="born"/>
          <xs:element ref="dead" minOccurs="0"/>
          <xs:element ref="qualification" minOccurs="0"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
</xs:schema>

We can now include both these fragments in our main schema:

<xs:include schemaLocation="simple-types.xsd"/>
<xs:include schemaLocation="complex-types.xsd"/>

We now have an included schema (complex-types.xsd), which references elements (such as author, character, or dead), that are defined in the main schema using datatypes defined in either simple-types.xsd or complex-types.xsd. This combination is perfectly valid for W3C XML Schema since the schema processor collects all the pieces it needs (or at least most of the pieces it needs since wildcards may introduce exceptions, discussed in Chapter 12, "Creating More Building Blocks Using Object-Oriented Features") before checking the references. This flexibility is powerful, handy for building flexible libraries, and eventually error-prone: a complex datatype, such as personType, will have the same children elements but these elements will have a different content model depending on the schema in which complex-types.xsd is included. While using these mechanisms, one must take care to keep track of the interdependencies that will be created!



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.