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


Book HomeXML SchemaSearch this book

8.2. Schema Inclusion with Redefinition

Inclusion does not provide any means to modify the definitions that are being included, and since they are considered global definitions after the import, they can't be modified afterward either. W3C XML Schema contains a feature that allows derivation of global types and group definitions during an inclusion; it keeps the same name after the derivation. Thus, the semantic of these redefinitions is "take this definition instead of the one you've found in the included schema, but make sure that it's a valid derivation so that applications are not too surprised about the change." These are implemented using the xs:redefine element with a schemaLocation attribute (like xs:include). Its children are component definitions that replace the definition found in the included schema. The definitions that are not included in the xs:redefine element are kept unchanged, which means that a xs:redefine with no child element is strictly equivalent to xs:include.

It is noteworthy that the effect of the redefinition is global to the resulting schema. References made to redefined components are all impacted by the modifications made to these components, even if they are made within the redefined schema.

8.2.1. Redefining of Simple and Complex Types

Simple and complex types are redefined by deriving them (by restriction for simple types and by restriction or extension for complex types) inside the xs:redefine element. We can apply this to our last example. The definition of bookTmp is currently used to describe the book element though derivation:

<xs:element name="book">
  <xs:complexType>
    <xs:complexContent>
      <xs:restriction base="bookTmp">
        <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 name="id" type="bookID"/>
        <xs:attribute ref="available"/>
      </xs:restriction>
    </xs:complexContent>
  </xs:complexType>
</xs:element>

Instead of doing this, we can also redefine the definition of the book complex type. The new schema to define the complex types is then:

<?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="book">
    <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>

The redefinition--note how a book complex type is redefined using a base type with the same name, which would be forbidden anywhere else--and usage of the book element looks like:

<xs:redefine schemaLocation="complex-types2.xsd">
  <xs:complexType name="book">
    <xs:complexContent>
      <xs:restriction base="book">
        <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 name="id" type="bookID"/>
        <xs:attribute ref="available"/>
      </xs:restriction>
    </xs:complexContent>
  </xs:complexType>
</xs:redefine>
          
<xs:element name="book" type="book"/>

8.2.2. Redefinition of Element and Attribute Groups

The redefinition of complex and simple types seems quite natural and should not be much of a surprise, since it builds on things we've discussed in detail in previous chapters. The new part of xs:redefine is that element and attribute groups--which cannot be derived--can also be redefined. Redefinition of element and attribute groups is done without any special schema element: a group redefinition that contains a reference to itself is considered an extension; otherwise, it's considered a restriction. These two methods have their own rules and semantics, which are similar but not identical to the rules and semantics of the derivation of complex types. These deserve a specific description. As we will see, the general principles are the same, and the asymmetry between extension and restriction is preserved for group redefinitions.

8.2.2.1. Extension

Group extensions are done by referencing the group somewhere in its redefinition. The semantic is, therefore, similar to the semantic of the derivation by extension of complex content complex types (some new content is added to the base type) with more flexibility. The location where the content of the base type is added may be chosen during the extension of a complex content complex type, and the new content is always appended after the content of the base type. If we have, for instance, a group definition such as:

<?xml version="1.0"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:group name="character">
    <xs:sequence>
      <xs:element ref="born"/>
      <xs:element ref="qualification"/>
    </xs:sequence>
  </xs:group>
</xs:schema>

We can redefine it to add the name element, which is missing at the beginning of the content:

<xs:redefine schemaLocation="character-group.xsd">
  <xs:group name="character">
    <xs:sequence>
      <xs:element ref="name"/>
      <xs:group ref="character"/>
    </xs:sequence>
  </xs:group>
</xs:redefine>
             
<xs:element name="character">
  <xs:complexType>
    <xs:group ref="character"/>
    <xs:attribute ref="id"/>
  </xs:complexType>
</xs:element>

We see that we have been able to choose the insertion point of the content of the base group, which is after the name element. The name element has been added; this is an enhancement over complex content complex type derivation.

This method of extending element or attribute groups is clearly underspecified in the Recommendation and should be used in its simplest form with caution to avoid interoperability issues. The Recommendation specifies that the minOccurs and maxOccurs attributes of the reference need to be exactly one, which shows a wish to include the content of the base group during an extension exactly one time. However, the wording of the Recommendation does not forbid inclusion of this reference in a branch that has a different number of occurrences, such as:

<xs:redefine schemaLocation="bar.xsd">
  <xs:group name="foo">
    <xs:sequence>
      <xs:sequence minOccurs="0">
        <xs:group ref="foo"/>
      </xs:sequence>
      <xs:element ref="bar"/>
    </xs:sequence>
  </xs:group>
</xs:redefine>

This is functionally equivalent to having minOccurs equal to zero on the group reference and allows content models without any occurrences of the base group. Since this is contrary to the philosophy behind derivations by extension, these kind of structures shouldn't be used. Similarly, the Recommendation does not forbid the use of another compositor other than a xs:sequence to redefine a group. However, since using xs:choice instead of xs:sequence leads to redefined groups in which the content of the base can be omitted, this is certainly something to avoid.

The references used to extend groups during a redefinition must be done at the top level of the group definition. The last thing to note about element group extensions is that even though its syntax uses a group reference to the group being defined, self references cannot be used in regular global group definitions for defining recursive content models. These need to be done at a lower level, such as:

<xs:group name="group">
  <!-- This group definition is *not* valid -->
  <xs:sequence>
    <xs:element name="foo">
      <xs:complexType>
        <xs:group ref="group" minOccurs="0"/>
      </xs:complexType>
    </xs:element>
    <xs:element name="bar" type="xs:token"/>
  </xs:sequence>
</xs:group>

8.2.2.2. Restriction

The redefinition of attribute and element groups by restriction is similar, in principle, to a derivation of a complex content complex type by restriction. A new definition of the group is given; this new definition must match the same criteria as that of a complex content complex type restriction, and must be a valid restriction of the base group. A content that matches the redefined group must always match the base group and the elements used by the new definition must be explicit restrictions of the elements used in the base group. If we have a group definition available, such as:

<?xml version="1.0"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:group name="author">
    <xs:sequence>
      <xs:element ref="name"/>
      <xs:element ref="born"/>
      <xs:element ref="dead" minOccurs="0"/>
      <xs:element name="nationality" type="xs:NMTOKEN" minOccurs="0"/>
    </xs:sequence>
  </xs:group>
</xs:schema>

We can redefine it to remove the element nationality, which is optional:

<xs:redefine schemaLocation="author.xsd">
  <xs:group name="author">
    <xs:sequence>
      <xs:element ref="name"/>
      <xs:element ref="born"/>
      <xs:element ref="dead" minOccurs="0"/>
    </xs:sequence>
  </xs:group>
</xs:redefine>
             
<xs:element name="author">
  <xs:complexType>
    <xs:group ref="author"/>
    <xs:attribute ref="id"/>
  </xs:complexType>
</xs:element>

Before we leave this subject, we need to note that the rules for restricting attribute groups are different than the rules for restricting complex types. The list of attributes must include all the attributes that are kept. (This is unlike complex type restrictions in which attributes that are not mentioned are considered unchanged.) If we have an attribute group such as:

<xs:attributeGroup name="commonAttributes">
  <xs:attribute name="id" type="xs:ID"/>
  <xs:attribute name="available" type="xs:boolean"/>
  <xs:attribute name="lang" type="xs:language"/>
</xs:attributeGroup>

If we want to restrict it to remove the available attribute through a redefinition, we then must repeat the definitions of the two other attributes:

<xs:redefine schemaLocation="attributes.xsd">
  <xs:attributeGroup name="commonAttributes">
    <xs:attribute name="id" type="xs:ID"/>
    <xs:attribute name="lang" type="xs:language"/>
  </xs:attributeGroup>
</xs:redefine>


Library Navigation Links

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