Chapter 4. Schema composition

It is convenient to think of a schema as an individual schema document. However, in XML Schema, a schema can be composed of components defined in one or more schema documents. This chapter explains how schema documents are assembled together to represent a schema through various mechanisms, including those built into XML Schema and processor-specific handling.

4.1. Modularizing schema documents

Breaking a schema document into multiple documents has a number of advantages such as promoting reuse, easing maintenance, and providing more granular access or versioning. The modularization can be based on subject areas, areas of responsibility, or the likely containers of reuse. How best to do it is a design decision that is covered in more detail in Section 21.5.2 on p. 557.

4.2. Defining schema documents

A schema document is most typically a physical XML file whose root element is schema, but this is only one form of schema document. A schema document may also be a fragment of another XML document referenced using a fragment identifier or an XPointer, a DOM tree in memory, or some other physical representation.

Each schema document describes components for at most one namespace, known as its target namespace. Several schema documents can describe components in the same namespace. Some schema documents have no target namespace at all. Figure 4–1 shows several schema documents in different namespaces.

Image

Figure 4–1. Schema documents

Each schema document is represented by a schema element whose syntax is shown in Table 4–1.

Table 4–1. XSD Syntax: schema document

Image
Image

As you can see from the content model, there are two distinct sections of a schema document. At the beginning, you specify all the includes, imports, redefines, and overrides that are used to refer to other schema documents. After that come the global, or top-level, components of the schema, such as elements, attributes, named types, and groups. These components can appear in the schema document in any order. Annotations can appear at the top level throughout the schema document.

4.3. Combining multiple schema documents

There are several methods of explicitly combining multiple schema documents.

• Includes are used to combine schema documents that have the same target namespace.

• Imports are used to combine schema documents that have different target namespaces.

• Redefines and overrides are used to combine schema documents that have the same target namespace, while revising the definition of the included components.

Includes and imports are covered in this section. Because of the complexities of redefines and overrides, all of Chapter 18 is devoted to them.

Although includes and imports are very common, they are not the only way to assemble schema documents. There is not always a “main” schema document that represents the whole schema. Some other alternatives are:

• The instance author can specify multiple schema locations in the instance, as described in Section 5.3.1 on p. 84.

• The processor can assemble schema documents from predefined locations.

• Multiple command-line parameters can be used to list the locations of the schema documents.

4.3.1. include

An include is used when you want to include other schema documents in a schema document that has the same target namespace. This provides for modularization of schema documents. For example, you may want to break your schema into several documents: two different order schema documents and a customer schema document. This is depicted in Figure 4–2.

Image

Figure 4–2. Includes

4.3.1.1. The syntax of includes

Includes are represented by include elements, whose syntax is shown in Table 4–2.

Table 4–2. XSD Syntax: include

Image

The include elements may only appear at the top level of a schema document, and they must appear at the beginning (along with the import, redefine, and override elements).

The schemaLocation attribute indicates where the included schema document is located. This attribute is required, although the location is not required to be resolvable. However, if it is resolvable, it must be a complete schema document.

Example 4–1 shows the use of include in a schema document. The schema author wants to use the type OrderNumType in the number element declaration. However, OrderNumType is defined in a different schema document. The include statement references the location of the schema document, ord2.xsd, that contains the definition of OrderNumType. In this example, the including document is referring to a simple type in the included document, but it could similarly refer to elements, attributes, complex types, or any other global components in the included document.

Example 4–1. Include


ord1.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           targetNamespace="http://datypic.com/ord">

  <xs:include schemaLocation="ord2.xsd"/>

  <xs:element name="order" type="OrderType"/>
  <xs:complexType name="OrderType">
    <xs:sequence>
      <xs:element name="number" type="OrderNumType"/>
      <!--...-->
    </xs:sequence>
  </xs:complexType>

</xs:schema>

ord2.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           targetNamespace="http://datypic.com/ord">

  <xs:simpleType name="OrderNumType">
    <xs:restriction base="xs:string"/>
  </xs:simpleType>
</xs:schema>


The schema documents ord1.xsd and ord2.xsd have the same target namespace. When you use includes, one of the following must be true:

• Both schema documents have the same target namespace.

• Neither schema document has a target namespace.

• The including schema document has a target namespace, and the included schema document does not have a target namespace.

There can be multiple include elements in a schema document. There can also be multiple levels of includes in schema documents. For example, ord1.xsd can include ord2.xsd, which includes cust.xsd, and so on. It is not an error to include the exact same schema document twice.

4.3.1.2. Chameleon includes

In the case where the included schema document has no target namespace, all components of the included schema document take on the namespace of the including schema document. These components are sometimes called chameleon components, because their namespace changes depending on where they are included. This is shown in Example 4–2.

Example 4–2. Chameleon include


ord1.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           targetNamespace="http://datypic.com/ord">

  <xs:include schemaLocation="cust.xsd"/>

  <xs:element name="order" type="OrderType"/>
  <xs:complexType name="OrderType">
    <xs:sequence>
      <xs:element name="number" type="xs:string"/>
      <xs:element name="customer" type="CustomerType"/>
      <!--...-->
    </xs:sequence>
  </xs:complexType>
</xs:schema>

cust.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:complexType name="CustomerType">
    <xs:sequence>
      <xs:element name="name" type="CustNameType"/>
      <!--...-->
    </xs:sequence>
  </xs:complexType>
  <xs:simpleType name="CustNameType">
    <xs:restriction base="xs:string"/>
  </xs:simpleType>
</xs:schema>


Note that in cust.xsd, the element declaration of name can reference the type CustNameType without any namespace. Even though these components will take on the target namespace of the ord.xsd schema document, the unqualified references between components in cust.xsd will be honored.

However, in ord1.xsd, the references to the cust.xsd components such as CustomerType do have to be qualified. This example works because ord1.xsd declares http://datypic.com/ord as the default namespace (in addition to being the target namespace). This means that any unprefixed references, such as the one to CustomerType, are considered to be in that namespace.

4.3.2. import

An import is used to tell the processor that you will be referring to components from other namespaces. For example, if you want to reference an attribute from another namespace in your complex type definition, or you want to derive your type from a type in another namespace, you must import this namespace. This is depicted in Figure 4–3.

Image

Figure 4–3. Import

Imports differ from includes in two important ways. First, includes only take place within a namespace, while imports take place across namespaces. The second, subtler distinction is their general purpose. The purpose of an include is specifically to pull in other schema documents, while the purpose of an import is to record a dependency on another namespace, not necessarily another schema document. Import does allow you to specify the location of a schema document for that namespace, but it is just a hint, and the processor is not required to try to resolve it.

4.3.2.1. The syntax of imports

Imports are represented by import elements, whose syntax is shown in Table 4–3.

Table 4–3. XSD Syntax: import

Image

The import elements may only appear at the top level of a schema document, and must appear at the beginning (along with the include, redefine, and override elements).

The namespace attribute indicates the namespace that you wish to import. If you do not specify a namespace, it means that you are importing components that are not in any namespace. The imported namespace cannot be the same as the target namespace of the importing schema document. If the importing schema document has no target namespace, the import element must have a namespace attribute.

The schemaLocation attribute provides a hint to the processor as to where to find a schema document that declares components for that namespace. If you do not specify a schemaLocation, it is assumed that the processor somehow knows where to find the schema document, perhaps because it was specified by the user or built into the processor. When schemaLocation is present and the processor is able to resolve the location to some resource, it must resolve to a schema document. That schema document’s target namespace must be equal to the value of the namespace attribute of the import element.

Looping references (ord1.xsd imports prod.xsd’s namespace, and prod.xsd imports ord1.xsd’s namespace) are also acceptable, because this just indicates the interdependence of the components.

Example 4–3 shows the use of import in a schema document. The schema author wants to use the type ItemsType in an element declaration. However, ItemsType is defined in a different namespace. The import statement references the namespace and location of the schema document that contains ItemsType. The declaration of items is then able to reference ItemsType using the appropriate prefix.

Note that the target namespace of prod.xsd must also be declared as a namespace in the importing schema document. This is necessary so that the items element declaration can refer to the type ItemsType using its appropriate namespace prefix.

Example 4–3. Import


ord1.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           xmlns:prod="http://datypic.com/prod"
           targetNamespace="http://datypic.com/ord">

  <xs:import namespace="http://datypic.com/prod"
             schemaLocation="prod.xsd"/>

  <xs:element name="order" type="OrderType"/>
  <xs:complexType name="OrderType">
    <xs:sequence>
      <xs:element name="number" type="xs:string"/>
      <xs:element name="items" type="prod:ItemsType"/>
      <!--...-->
    </xs:sequence>
  </xs:complexType>
</xs:schema>

prod.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/prod"
           targetNamespace="http://datypic.com/prod">

  <xs:complexType name="ItemsType">
    <xs:sequence>
      <xs:element name="product" type="ProductType"/>
    </xs:sequence>
  </xs:complexType>
  <!-- ... -->
</xs:schema>


4.3.2.2. Multiple levels of imports

As with includes, imports can be chained together. That is, ord1.xsd can import prod.xsd which itself imports a third schema document, extension.xsd. However, imports are subtly different from includes in this regard. With multilevel includes, ord1.xsd would automatically be able to refer to components from extension.xsd. With imports, if ord1.xsd wants to directly refer to components in extension.xsd, it would have to also directly import the target namespace of extension.xsd. This is because the import is also used to record a dependency on another namespace, not just incorporate another schema document.

This is shown in Example 4–4, where ord1.xsd directly references ext:ExtensionType from extension.xsd. This requires it to import extension.xsd (or at least the ext namespace), which it does. If it did not directly refer to a component in that namespace, it would not need to import it.

Example 4–4. Multiple levels of import


ord1.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           xmlns:prod="http://datypic.com/prod"
           xmlns:ext="http://datypic.com/ext"
           targetNamespace="http://datypic.com/ord">

  <xs:import namespace="http://datypic.com/prod"
             schemaLocation="prod.xsd"/>
  <xs:import namespace="http://datypic.com/ext"
             schemaLocation="extension.xsd"/>

  <xs:element name="order" type="OrderType"/>
  <xs:complexType name="OrderType">
    <xs:sequence>
      <xs:element name="number" type="xs:string"/>
      <xs:element name="items" type="prod:ItemsType"/>
      <!--...-->
      <xs:element name="extension" type="ext:ExtensionType"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

prod.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/prod"
           xmlns:ext="http://datypic.com/ext"
           targetNamespace="http://datypic.com/prod">

  <xs:import namespace="http://datypic.com/ext"
             schemaLocation="extension.xsd"/>

  <xs:complexType name="ItemsType">
    <xs:sequence>
      <!-- ... -->
      <xs:element name="extension" type="ext:ExtensionType"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

extension.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ext"
           targetNamespace="http://datypic.com/ext">

  <xs:complexType name="ExtensionType">
    <!-- ... -->
  </xs:complexType>
</xs:schema>


4.3.2.3. Multiple imports of the same namespace

It is legal to have multiple imports of the same namespace in the same schema document or a set of assembled schema documents. If they refer to the same schema document, the processor will determine that they are the same components and will not raise errors about duplicate definitions. This was the case in Example 4–4, where both ord1.xsd and prod.xsd import the same schema document, extension.xsd.

However, if multiple imports of the same namespace refer to different schema documents, most processors will ignore all but the first one they encounter. This is permissible (if not always convenient) because imports, unlike includes, are considered to be just “hints” that the processor can choose to ignore.

Suppose, for example, that a schema document root.xsd declares a root element root that has two children: orderSummary and orderDetails. The two child elements are in the same namespace but declared in different schema documents. You might expect to be able to import both Summary.xsd and Detail.xsd into root.xsd, as shown in Example 4–5. However, when you validate an instance against root.xsd, most processors will ignore the import of Detail.xsd and raise an error because no declaration of orderDetails could be found.

Example 4–5. Multiple imports of the same namespace


root.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/root"
           xmlns:ord="http://datypic.com/ord"
           targetNamespace="http://datypic.com/root">

  <xs:import namespace="http://datypic.com/ord"
             schemaLocation="Summary.xsd"/>
  <xs:import namespace="http://datypic.com/ord"
             schemaLocation="Detail.xsd"/>

  <xs:element name="root" type="RootType"/>
  <xs:complexType name="RootType">
    <xs:sequence>
      <xs:element ref="ord:orderSummary"/>
      <xs:element ref="ord:orderDetails"/>
      <!--...-->
    </xs:sequence>
  </xs:complexType>

</xs:schema>

Summary.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           targetNamespace="http://datypic.com/ord">

  <xs:element name="orderSummary"/>
  <!-- ... -->
</xs:schema>

Detail.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           targetNamespace="http://datypic.com/ord">

  <xs:element name="orderDetails"/>
  <!-- ... -->
</xs:schema>


One way to get around this is to declare a single schema document, sometimes called a proxy schema, for the ord namespace and include all the necessary schema documents in that namespace, as shown in Example 4–6. This will work because there is only one import for that namespace in root.xsd and the includes in Orders.xsd cannot be ignored.

Example 4–6. Proxy schema to avoid multiple imports


root.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/root"
           xmlns:ord="http://datypic.com/ord"
           targetNamespace="http://datypic.com/root">

  <xs:import namespace="http://datypic.com/ord"
             schemaLocation="Orders.xsd"/>

  <xs:element name="root" type="RootType"/>
  <xs:complexType name="RootType">
    <xs:sequence>
      <xs:element ref="ord:orderSummary"/>
      <xs:element ref="ord:orderDetails"/>
      <!-- ... -->
    </xs:sequence>
  </xs:complexType>

</xs:schema>

Orders.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           targetNamespace="http://datypic.com/ord">

  <xs:include schemaLocation="Summary.xsd"/>
  <xs:include schemaLocation="Detail.xsd"/>
  <!-- ... -->
</xs:schema>


4.4. Schema assembly considerations

Whether you are using includes, imports, redefines, or overrides, there are several factors to take into consideration when combining multiple schema documents into a single schema. These factors are discussed in this section.

4.4.1. Uniqueness of qualified names

The qualified names of globally declared components must be unique in the schema, not just a schema document. When assembling a schema from multiple schema documents, be careful not to introduce duplicate qualified names. Example 4–7 shows two schema documents, both of which contain global element declarations for order.

Example 4–7. Illegal duplication of element names


ord1.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           targetNamespace="http://datypic.com/ord">
  <xs:include schemaLocation="ord2.xsd"/>
  <xs:element name="order" type="OrderType"/>
</xs:schema>

ord2.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           targetNamespace="http://datypic.com/ord">
  <xs:element name="order" type="OrderType"/>
</xs:schema>


It is not illegal for two schema documents to exist that have duplicate names, since they may be used at different times in different situations. However, since ord1.xsd includes ord2.xsd, they will be used together, and this is illegal. Remember, the qualified name includes the namespace name, so this example would be valid if the two schema documents had different target namespaces (and ord2.xsd had been imported rather than included).

This rule holds true for all named, global components, including attributes, simple and complex types, named model groups, attribute groups, identity constraints, and notations. The uniqueness of qualified names is within the type of component. For example, it is illegal to have two global element declarations for order, but it is legal to have both an element declaration and a simple type definition with that name. However, simple and complex types cannot share the same qualified name.

4.4.2. Missing components

In some cases, declarations or definitions will refer to components that are outside the schema document. In Example 4–8, the order element declaration uses the type OrderType that is not defined in the schema document. This is not illegal unless a processor tries to use that declaration and cannot find a definition of OrderType.

Example 4–8. Missing component


<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/ord"
           targetNamespace="http://datypic.com/ord">

  <xs:element name="number" type="xs:integer"/>
  <xs:element name="order" type="OrderType"/>
</xs:schema>


In this case, the processor might obtain access to a schema document that contains the OrderType definition by some other means, as described in Section 4.3 on p. 61.

Even if a schema document containing the definition of OrderType is never found, the processor will still be able to validate a number element. The fact that there are unresolved references in the schema is only an error if such a reference is directly involved in the validation.

4.4.3. Schema document defaults

As we saw in Section 4.2 on p. 58, schema documents can have four defaults specified: attributeFormDefault, elementFormDefault, blockDefault, and finalDefault. As schema documents are assembled into schemas, these defaults are not overridden in any way. The defaults of a schema document still apply to all components defined or declared in that particular schema document. For example, if ord2.xsd has elementFormDefault set to unqualified, all of the local element declarations in ord2.xsd will have unqualified names, even if ord2.xsd is included in another schema document that has elementFormDefault set to qualified.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.111.203