In the previous chapter, we saw how to define new complex types that are not specifically derived from another type. This chapter covers the complexities of deriving complex types from other types, both complex and simple.
XML Schema allows you to derive a new complex type from an existing simple or complex type. While it is always possible to make a copy of an existing type and modify it to suit your needs, using type derivation has a number of advantages:
• Subsetting. If you want to define a more restrictive subset of a schema, the best way to do this is using restriction. Your schema processor will validate that you have in fact defined a legal subset. It also allows future modifications to the original types to be reflected in your derived types automatically.
• Safe extensions. If you want to add to existing schema components, XML Schema’s extension mechanism ensures that you do that in such a way that an application can still handle the original definition.
• Type substitution. Derived types can substitute for their ancestor types in instances, which is a very flexible way to support variations in content.
• Reuse. If several types share the same basic structure but have minor differences, it makes sense to reuse the similar parts. This makes maintenance easier and ensures consistency. Type derivation is one way to reuse content model fragments and attributes.
• Convenience in a type-aware language. Languages such as XSLT 2.0 and XQuery are type-aware, which allows you to define processes on base types that may be passed down to their derived types. For example, XSLT 2.0 lets you apply a specific template to “anything of type AddressType
or any type derived from it.”
Complex types are derived from other types either by restriction or extension.
• Restriction, as the name suggests, restricts the valid contents of a type. The values for the new type are a subset of those for the base type. All values of the restricted type are also valid according to the base type.
• Extension allows for adding children and/or attributes to a type. Values of the base type are not necessarily valid for the extended type, since required elements or attributes may be added.
It is not possible to restrict and extend a complex type at the same time, but it is possible to do this in two steps, first extending a type, and then restricting the extension, or vice versa. However, when doing this, it is not legal to remove something in a restriction and then use extension to add it back in an incompatible way; for example, you cannot re-add an element declaration with a different type.
A complex type always has either simple content or complex content. Simple content means that it has only character data content, with no children. Complex content encompasses the other three content types (mixed, element-only, and empty) that were covered in Section 12.3 on p. 262. A complex type is derived from another type using either a simpleContent
element or a complexContent
element.
A simpleContent
element is used when deriving a complex type from a simple type, or from another complex type with simple content. This can be done to add or remove attribute declarations, or to further restrict the simple type of the character content. If a complex type has simple content, all types derived from it, directly or indirectly, must also have simple content. It is impossible to switch from simple content to complex content by deriving a type with child elements. Table 13–1 shows the syntax for a simpleContent
element. It contains either an extension
or a restriction
child element. These elements are discussed in Sections 13.4.1 on p. 306 and 13.5.1 on p. 317, respectively.
Table 13–1. XSD Syntax: simple content definition
A complexContent
element is used when deriving a complex type from another complex type which itself has complex content. This includes mixed, element-only, and empty content types. This can be done to add or remove parts of the content model as well as attribute declarations. Table 13–2 shows the syntax for a complexContent
element. It too must contain either an extension
or a restriction
, but with definitions different from their counterparts in simpleContent
. These elements are discussed in Sections 13.4.2 on p. 307 and 13.5.2 on p. 318, respectively.
Table 13–2. XSD Syntax: complex content definition
If complexContent
has a mixed
attribute, that value is used. If it has no mixed
attribute, the mixed
attribute of complexType
is used. If neither element has a mixed
attribute, the default for mixed
is false
.
Complex types may be extended by adding to the content model and to the attribute declarations. Table 13–3 shows the legal extensions for each content type.
Table 13–3. Legal extensions by content type
The only purpose of simple content extensions is to add attribute declarations. It is not possible to extend the value space of the simple content, just as it is not possible to extend the value space of a simple type. Table 13–4 shows the syntax for an extension
element that is the child of a simpleContent
element.
Table 13–4. XSD Syntax: simple content extension
Example 13–1. Simple content extension
Schema:
<xs:complexType name="SizeType">
<xs:simpleContent>
<xs:extension base="xs:integer">
<xs:attribute name="system" type="xs:token"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
Instance:
<size system="US-DRESS">10</size>
Example 13–1 shows the definition of a complex type SizeType
that has simple content. It has a content type of integer
, and it has been extended to add the system
attribute declaration. A valid instance is also shown.
Complex content extensions allow you to add to the end of the content model of the base type. You can also add attribute declarations, but you cannot modify or remove the base type’s attribute declarations. Table 13–5 shows the syntax for an extension
element that is the child of a complexContent
element.
Table 13–5. XSD Syntax: complex content extension
When defining a complex content extension, you do not need to copy the content model from the base type. The processor handles complex content extensions by appending the new content model after the base type’s content model, as if they were together in a sequence
group.
Example 13–2 shows a complex content extension. The complex type ProductType
has two children: number
and name
. The type ShirtType
extends ProductType
by adding a choice
group containing two additional children: size
and color
.
The effective content model of ShirtType
is shown in Example 13–3. It is as if there were a sequence
group at the top level of the complex type, which contains the content model of ProductType
, followed by the content model extensions specified in the ShirtType
definition itself.
Example 13–2. Complex content extension
<xs:complexType name="ProductType">
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ShirtType">
<xs:complexContent>
<xs:extension base="ProductType">
<xs:choice maxOccurs="unbounded">
<xs:element name="size" type="xs:integer"/>
<xs:element name="color" type="xs:string"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Example 13–3. Effective content model of ShirtType
<xs:complexType name="ShirtType">
<xs:sequence>
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
<xs:choice maxOccurs="unbounded">
<xs:element name="size" type="xs:integer"/>
<xs:element name="color" type="xs:string"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
Since extending requires the addition of an “artificial” sequence
group, extension does not work well as a way to add elements to choice
groups. Example 13–4 shows a type ExpandedItemsType
that extends ItemsType
to add new product types. Intuitively, you may think that the two additional element references, sweater
and suit
, are added to the choice
group, allowing a choice among the five element declarations. In fact, the effective content model of ExpandedItemsType
is a sequence
group that contains two choice
groups. As a result, ExpandedItemsType
will require any of the shirt
, hat
, and umbrella
elements to appear before any of the sweater
or suit
elements.
Example 13–4. choice group extension
<xs:complexType name="ItemsType">
<xs:choice maxOccurs="unbounded">
<xs:element ref="shirt"/>
<xs:element ref="hat"/>
<xs:element ref="umbrella"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="ExpandedItemsType">
<xs:complexContent>
<xs:extension base="ItemsType">
<xs:choice maxOccurs="unbounded">
<xs:element ref="sweater"/>
<xs:element ref="suit"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
A better way to extend a choice
group is through substitution groups. See Section 22.2.4 on p. 607 for more information.
In version 1.0, extension is not allowed for all
groups. In version 1.1, this constraint has been relaxed, and complex types that contain all
groups can be extended, provided that the derived type also uses an all
group, as shown in Example 13–5.
Example 13–5. all group extension
<xs:complexType name="ProductType">
<xs:all>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:all>
</xs:complexType>
<xs:complexType name="ShirtType">
<xs:complexContent>
<xs:extension base="ProductType">
<xs:all>
<xs:element name="size" type="xs:integer"/>
<xs:element name="color" type="xs:string"/>
</xs:all>
</xs:extension>
</xs:complexContent>
</xs:complexType>
The effective content model in this case is one big all
group, shown in Example 13–6, not two all
groups inside a sequence
.
When extending an all
group with another all
group, both groups must have the same value for minOccurs
(if any). The minOccurs
of the effective resulting group is the minOccurs
of both groups. In Example 13–5, the value for both groups defaults to 1
, so the group shown in Example 13–6 does also. Alternatively, both of the all
groups could have, for example, minOccurs="0"
, in which case the effective minOccurs
is 0
.
Example 13–6. Effective content model of ShirtType with all groups combined
<xs:complexType name="ShirtType">
<xs:all>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="size" type="xs:integer"/>
<xs:element name="color" type="xs:string"/>
</xs:all>
</xs:complexType>
It is possible to extend a type that has open content, or to add open content in an extension. There are several possible scenarios:
• If openContent
is specified for the base type but not the derived type, the openContent
is inherited as is from the base type.
• If openContent
is specified for the derived type but not the base type, it is considered to be added in the derived type.
• If it is specified in both the base type and the derived type, it must be the same or less restrictive in the derived type. For example, if mode
is suffix
in the base type but interleave
in the derived type, this is legal because it is less constraining. The opposite is not legal; attempting to turn interleave
mode into suffix
mode means creating a more restrictive type. In addition, the namespace allowances on the derived type must be the same as, or a superset of, those allowed for the base type.
Example 13–7 shows the case where openContent
appears in both types. This example is legal because the mode is equally constraining and the list of allowed namespaces is less constraining.
Note that since the mode
is suffix
, in an instance of ShirtType
the replacement elements for the wildcard will go at the very end, after the color
element. Even though openContent
is defined for the base type, it is not possible to include replacement elements directly after name
, where they would appear in an instance of ProductType
.
Example 13–7. Extending open content
<xs:complexType name="ProductType">
<xs:openContent mode="suffix">
<xs:any namespace="##other" processContents="lax"/>
</xs:openContent>
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ShirtType">
<xs:complexContent>
<xs:extension base="ProductType">
<xs:openContent mode="suffix">
<xs:any namespace="##any" processContents="lax"/>
</xs:openContent>
<xs:sequence>
<xs:element name="size" type="xs:integer"/>
<xs:element name="color" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Complex types with mixed content can be extended, but the derived type must also have mixed content. The extension is treated the same way as it is for element-only complex types described in the previous section. It is illegal to extend a mixed content type to result in an element-only content type. The reverse is also true; it is illegal to extend an element-only content type to result in a mixed content type.
When extending a mixed content type, you must also specify the mixed
attribute for the derived type. Example 13–8 shows a mixed complex type LetterType
that is extended to derive another mixed complex type, ExtendedLetterType
.
Example 13–8. Mixed content extension
<xs:complexType name="LetterType" mixed="true">
<xs:sequence>
<xs:element name="custName" type="xs:string"/>
<xs:element name="prodName" type="xs:string"/>
<xs:element name="prodSize" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ExtendedLetterType" mixed="true">
<xs:complexContent>
<xs:extension base="LetterType">
<xs:sequence>
<xs:element name="prodNum" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Complex types with empty content can be extended to add a content model and/or attribute declarations. Example 13–9 shows an empty complex type named ItemType
, which is extended by ProductType
to add a sequence
group containing two element declarations.
Example 13–9. Empty content extension
<xs:complexType name="ItemType">
<xs:attribute name="routingNum" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="ProductType">
<xs:complexContent>
<xs:extension base="ItemType">
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
When defining an extension, you may specify additional attribute declarations in the derived type’s definition. When extending complex types, attributes are always passed down from the base type to the new type. It is not necessary (or even legal) to repeat any attribute declarations from the base type or any other ancestors in the new type definition. It is not possible to modify or remove any attribute declarations from the base type in an extension.
Example 13–10 shows the definition of ProductType
, which extends ItemType
. It adds two attribute declarations: effDate
and lang
. It may be surprising that lang
is legal, since it appears in the base type definition. This is because the new lang
is in a different namespace, so it is allowed. The lang
in the base type definition must be prefixed when it appears in the instance, as shown in the instance example.
Example 13–10. Attribute extension
Schema:
<xs:complexType name="ItemType">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute ref="xml:lang"/>
</xs:complexType>
<xs:complexType name="ProductType">
<xs:complexContent>
<xs:extension base="ItemType">
<xs:attribute name="effDate" type="xs:date"/>
<xs:attribute name="lang" type="xs:language"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Instance:
<product id="prod557"
xml:lang="en"
lang="en"
effDate="2001-04-12"/>
If an attribute wildcard is specified in an extension, and there is no attribute wildcard specified in the definition of its base type or any of its ancestors, it is a straightforward matter of using the one attribute wildcard. If, however, one or more of the ancestor types have an attribute wildcard, the effective wildcard is the union of the new wildcard and all ancestor wildcards. The value for processContents
is taken from the new derived type, and the union of the namespace constraints of the attribute wildcards is used. A simple rule of thumb is that if an attribute is an allowed replacement attribute for at least one of the attribute wildcards, it can be used.
Example 13–11 shows the definition of DerivedType
that extends BaseType
. Both DerivedType
and BaseType
have attribute wildcards specified, with different values for processContents
and namespace
.
Example 13–12 shows the effective definition of DerivedType
, after taking the union of the two attribute wildcards. Note that the value of processContents
is taken from the derived type, and the namespace list is the union of those of the two types.
Example 13–11. Attribute wildcard extension
<xs:complexType name="BaseType">
<xs:anyAttribute processContents="lax"
namespace="##local
http://datypic.com/prod"/>
</xs:complexType>
<xs:complexType name="DerivedType">
<xs:complexContent>
<xs:extension base="BaseType">
<xs:anyAttribute processContents="strict"
namespace="##targetNamespace
http://www.w3.org/1999/xhtml"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Example 13–12. Effective attribute wildcard
<xs:complexType name="DerivedType">
<xs:anyAttribute processContents="strict"
namespace="##local
http://datypic.com/prod
##targetNamespace
http://www.w3.org/1999/xhtml"/>
</xs:complexType>
Complex types may be restricted by eliminating or restricting attribute declarations as well as by subsetting content models. When restriction is used, instances of the derived type will always be valid for the base type as well. Table 13–6 shows the legal restrictions for each content type.
Table 13–6. Legal restrictions by content type
The purpose of a simple content restriction is to restrict the simple content and/or attribute declarations of a complex type. Table 13–7 shows the syntax of a restriction
element that is the child of a simpleContent
element. The base
attribute must refer to a complex type with simple content, not a simple type. This is because a restriction of a simple type is another simple type, not a complex type.
Table 13–7. XSD Syntax: simple content restriction
In Example 13–1 we defined a complex type SizeType
that had simple content, and declared a system
attribute. Example 13–13 shows a new type, SmallSizeType
, which restricts SizeType
. It restricts both the content, by applying the minInclusive
and maxInclusive
facets, and the system
attribute declaration, by making it required. See Section 13.5.5 on p. 333 for more information on restricting attribute declarations.
Example 13–13. Simple content restriction
<xs:complexType name="SmallSizeType">
<xs:simpleContent>
<xs:restriction base="SizeType">
<xs:minInclusive value="2"/>
<xs:maxInclusive value="6"/>
<xs:attribute name="system" type="xs:token"
use="required"/>
</xs:restriction>
</xs:simpleContent>
</xs:complexType>
Complex content restrictions allow you to restrict the content model and/or attribute declarations of a complex type. Table 13–8 shows the syntax of a restriction
element that is the child of a complexContent
element.
Table 13–8. XSD Syntax: complex content restriction
When restricting complex content, it is necessary to repeat all of the content model that is desired. The full content model specified in the restriction becomes the content model of the derived type. This content model must be a restriction of the content model of the base type. This means that all instances of the new restricted type must also be valid for the base type.
Example 13–14 shows the definition of a complex type Restricted-ProductType
that restricts the complex type ProductType
by eliminating the size
and color
child elements. This is legal because all instances of RestrictedProductType
are also valid according to ProductType
. However, if the size
element declaration had a minOccurs
value of 1
in ProductType
, the restriction would not be legal, because values of RestrictedProductType
would not be valid according to ProductType
; they would be missing a required element.
Example 13–14. Complex content restriction
<xs:complexType name="ProductType">
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="size" type="xs:integer" minOccurs="0"/>
<xs:element name="color" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RestrictedProductType">
<xs:complexContent>
<xs:restriction base="ProductType">
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
In most cases, you can use common sense to determine whether a restriction is legal. If you can think of a valid instance of the derived type that is not valid for the base type, there is a problem with your restriction. In case you want to do a more thorough analysis, the rest of this section describes the rules for legal content model restrictions that are detailed in version 1.0.
In version 1.1, these specific rules have been replaced with a general statement that the derived type must be more restrictive than the base type. However, the following sections may still be useful as a guideline for the types of restrictions that can be defined.
Any meaningless groups may be eliminated. This includes:
• Groups with no children
• Groups that have minOccurs
and maxOccurs
equal to 1
, and only have one child
• sequence
groups that have minOccurs
and maxOccurs
equal to 1
and are contained in another sequence
group (this is illustrated in Example 13–15)
• choice
groups that have minOccurs
and maxOccurs
equal to 1
and are contained in another choice
group
Example 13–15. Eliminating meaningless groups
Base group:
<xs:sequence>
<xs:sequence>
<xs:element name="a"/>
<xs:element name="b"/>
</xs:sequence>
</xs:sequence>
<xs:sequence>
<xs:element name="a"/>
<xs:element name="b"/>
</xs:sequence>
When restricting a specific element declaration, several rules apply.
• The occurrence constraints in the derived element declaration must be equal or more restrictive. This is illustrated by a
in Example 13–16.
• The type in the derived element declaration must be a restriction of the type in the base element declaration (or they must have the same type). This is illustrated by c
in Example 13–16.
• If the base element declaration specified a fixed value, the derived element declaration must specify the same fixed value. This is illustrated by b
in Example 13–16.
• The identity constraints (key
, keyref
, unique
) in the derived element declaration must be more restrictive than those of the base element declaration.
• The contents of the block
attribute of the derived element declaration must be a subset of that of the base element declaration.
• If the base element declaration had nillable
set to false
, the derived element declaration cannot reverse that property.
Example 13–16. Restricting element declarations
Base group:
<xs:sequence>
<xs:element name="a" maxOccurs="3"/>
<xs:element name="b" fixed="bValue"/>
<xs:element name="c" type="xs:string"/>
</xs:sequence>
Legal restriction:
<xs:sequence>
<xs:element name="a" maxOccurs="2"/>
<xs:element name="b" fixed="bValue"/>
<xs:element name="c" type="xs:token"/>
</xs:sequence>
Illegal restriction:
<xs:sequence>
<xs:element name="a" maxOccurs="4"/>
<xs:element name="b" fixed="newValue"/>
<xs:element name="c" type="xs:integer"/>
</xs:sequence>
When replacing an element wildcard with specific element declarations or a group of element declarations, these derived declarations must yield valid replacement elements for the wildcard, in terms of their namespace and occurrence constraints. This is illustrated in Example 13–17 which shows a restriction that is illegal for two reasons. First, b
is illegal because it is in the same namespace as the other elements (while the wildcard says ##other
). Second, two replacement elements are declared, but the wildcard has a maxOccurs
of 1
.
Example 13–17. Replacing a wildcard with element declarations
Base group:
<xs:sequence>
<xs:element name="a"/>
<xs:any namespace="##other" maxOccurs="1"/>
</xs:sequence>
Legal restriction:
<xs:sequence>
<xs:element name="a"/>
<xs:element ref="otherns:b"/>
</xs:sequence>
Illegal restriction:
<xs:sequence>
<xs:element name="a"/>
<xs:element ref="b"/>
<xs:element name="c"/>
</xs:sequence>
When replacing an element wildcard with another element wildcard, the derived wildcard’s namespace constraint must be a subset of the base wildcard’s namespace constraint, as described in Section 13.5.6 on p. 335. Also, the occurrence constraints must be a subset. This is illustrated in Example 13–18, which shows a restriction that is illegal because neither the namespace constraint nor the occurrence constraint specifies a subset of what is allowed by the base wildcard.
Example 13–18. Replacing a wildcard with another wildcard
Base wildcard:
<xs:any namespace="urn:a:1 urn:a:2" maxOccurs="2"/>
Legal restriction:
<xs:any namespace="urn:a:1" maxOccurs="1"/>
Illegal restriction:
<xs:any namespace="##other" maxOccurs="3"/>
When replacing a group with an element declaration, it must be valid for an instance of that group to just have that one element child. For example, a choice
group that contains that element declaration, or a sequence
group declaring all other elements optional, would work as base groups in this case. This is illustrated in Example 13–19.
When replacing a group with another group, the occurrence constraints must become more restrictive. For example, if the maxOccurs
value for a group in the base type is 5
, the group in the derived type cannot have a maxOccurs
that is greater than 5
. This is illustrated in Example 13–20.
Example 13–19. Replacing a group with an element declaration
Base group:
<xs:sequence>
<xs:element name="a"/>
<xs:element name="b" minOccurs="0"/>
</xs:sequence>
Legal restriction:
<xs:element name="a"/>
Example 13–20. Restricting occurrence constraints of a group
Base group:
<xs:sequence minOccurs="2" maxOccurs="5">
<xs:element name="a"/>
<xs:element name="b"/>
</xs:sequence>
Legal restriction:
<xs:sequence minOccurs="3" maxOccurs="4">
<xs:element name="a"/>
<xs:element name="b"/>
</xs:sequence>
Illegal restriction:
<xs:sequence minOccurs="0" maxOccurs="6">
<xs:element name="a"/>
<xs:element name="b"/>
</xs:sequence>
When replacing a group with a group of the same kind (all
, choice
, or sequence
), the order of the children (element declarations and groups) must be preserved. This is true even for all
and choice
groups, when the order is not significant for validation. This is illustrated in Example 13–21.
Example 13–21. Maintaining the order of the children in an all group
Base group:
<xs:all>
<xs:element name="a"/>
<xs:element name="b" minOccurs="0"/>
<xs:element name="c"/>
</xs:all>
Legal restriction:
<xs:all>
<xs:element name="a"/>
<xs:element name="c"/>
</xs:all>
Illegal restriction:
<xs:all>
<xs:element name="c"/>
<xs:element name="a"/>
</xs:all>
When restricting an all
or sequence
group, if any child element declarations or groups are not included in the derived group, they must be optional in the base group. This is illustrated in Example 13–22.
Example 13–22. Restricting an all group
Base group:
<xs:all>
<xs:element name="a"/>
<xs:element name="b" minOccurs="0"/>
<xs:element name="c"/>
</xs:all>
Legal restriction:
<xs:all>
<xs:element name="a"/>
<xs:element name="c"/>
</xs:all>
<xs:all>
<xs:element name="a"/>
<xs:element name="b"/>
</xs:all>
When replacing a choice
group with another choice
group, the child element declarations of the derived group must be a subset of those in the base group. This is illustrated in Example 13–23.
Example 13–23. Restricting a choice group
Base group:
<xs:choice>
<xs:element name="a"/>
<xs:element name="b"/>
<xs:element name="c"/>
</xs:choice>
Legal restriction:
<xs:choice>
<xs:element name="a"/>
<xs:element name="c"/>
</xs:choice>
Illegal restriction:
<xs:choice>
<xs:element name="a"/>
<xs:element name="d"/>
</xs:choice>
When replacing an all
group with a sequence
group, each element declaration in the all
group cannot appear more than once in the sequence
group, or appear with maxOccurs
greater than 1
. This is illustrated in Example 13–24.
Example 13–24. Replacing an all group with a sequence group
Base group:
<xs:all>
<xs:element name="a"/>
<xs:element name="b" minOccurs="0"/>
<xs:element name="c"/>
</xs:all>
Legal restriction:
<xs:sequence>
<xs:element name="a"/>
<xs:element name="c"/>
</xs:sequence>
Illegal restriction:
<xs:sequence>
<xs:element name="a"/>
<xs:element name="b"/>
<xs:element name="c" minOccurs="2"/>
</xs:sequence>
When replacing a choice
group with a sequence
group, the maxOccurs
of the choice
group must be enough to cover the number of elements that the sequence
group will yield. This is illustrated in Example 13–25.
Example 13–25. Replacing a choice group with a sequence group
Base group:
<xs:choice maxOccurs="2">
<xs:element name="a"/>
<xs:element name="b"/>
<xs:element name="c"/>
</xs:choice>
Legal restriction:
<xs:sequence>
<xs:element name="a"/>
<xs:element name="c"/>
</xs:sequence>
Illegal restriction:
<xs:sequence>
<xs:element name="a"/>
<xs:element name="b"/>
<xs:element name="c"/>
</xs:sequence>
It is possible to restrict a type that has open content, but as with the rest of the content model, it is not inherited automatically. If open content is desired in the restricted type, it is necessary to respecify it. In order to be a legal restriction, the open content in the restricted type should not be more permissive than the base type, in terms of both the mode and the namespace constraint.
Example 13–26 shows the two examples of restricting open content. The first, LegalDerivedType
, is legal because suffix
mode is as permissive as the base type, and the namespace constraint is more restrictive in the derived type (one choice instead of two). The second example, IllegalDerivedType
, is illegal because interleave
mode is more permissive than the base type, and the namespace constraint of ##any
is also more permissive.
Example 13–26. Restricting open content
Base group:
<xs:complexType name="BaseType">
<xs:openContent mode="suffix">
<xs:any namespace="http://datypic.com/prod
http://datypic.com/ord"/>
</xs:openContent>
<xs:sequence>
<xs:element name="a" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
Legal restriction:
<xs:complexType name="LegalDerivedType">
<xs:complexContent>
<xs:restriction base="BaseType">
<xs:openContent mode="suffix">
<xs:any namespace="http://datypic.com/prod"/>
</xs:openContent>
<xs:sequence>
<xs:element name="a" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
Illegal restriction:
<xs:complexType name="IllegalDerivedType">
<xs:complexContent>
<xs:restriction base="BaseType">
<xs:openContent mode="interleave">
<xs:any namespace="##any"/>
</xs:openContent>
<xs:sequence>
<xs:element name="a" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
It is also legal to remove the openContent
element completely in a restriction, since that is less permissive. As you would expect, it is not legal to add one unless the mode
is none
.
Complex types with mixed content may be restricted to derive other complex types with mixed content or with element-only content. The reverse is not true: It is not possible to restrict an element-only complex type to result in a complex type with mixed content.
If you want the derived type to be mixed, you must specify the mixed
attribute for the derived type, since the quality of being mixed is not inherited from the base type. Example 13–27 shows a mixed complex type LetterType
that is restricted to derive another mixed complex type, RestrictedLetterType
.
Example 13–27. Mixed content restriction
<xs:complexType name="LetterType" mixed="true">
<xs:sequence>
<xs:element name="custName" type="xs:string"/>
<xs:element name="prodName" type="xs:string"/>
<xs:element name="prodSize" type="xs:integer" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RestrictedLetterType" mixed="true">
<xs:complexContent>
<xs:restriction base="LetterType">
<xs:sequence>
<xs:element name="custName" type="xs:string"/>
<xs:element name="prodName" type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
It is also possible to restrict a mixed content type to derive an empty content type, or even a complex type with simple content. This is only legal if all of the children in the content model of the base type are optional. Example 13–28 shows a slightly different LetterType
definition where the sequence group is optional. The derived type RestrictedLetterType
will allow only character data content of type string
, with no children. Note that this is the only case where a restriction
element must have both a base
attribute and a simpleType
child.
Example 13–28. Mixed content restricted to simple content
<xs:complexType name="LetterType" mixed="true">
<xs:sequence minOccurs="0">
<xs:element name="custName" type="xs:string"/>
<xs:element name="prodName" type="xs:string"/>
<xs:element name="prodSize" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RestrictedLetterType">
<xs:simpleContent>
<xs:restriction base="LetterType">
<xs:simpleType>
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:restriction>
</xs:simpleContent>
</xs:complexType>
Complex types with empty content may be restricted, but the restriction applies only to the attributes. The derived type must also have empty content. Example 13–29 shows a restriction of the empty complex type ItemType
. The only restriction is applied to the type of the routingNum
attribute.
Example 13–29. Empty content restriction
<xs:complexType name="ItemType">
<xs:attribute name="routingNum" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="RestrictedItemType">
<xs:complexContent>
<xs:restriction base="ItemType">
<xs:attribute name="routingNum" type="xs:short"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
When defining a restriction, you may restrict or eliminate attribute declarations of the base type. All attribute declarations are passed down from the base type to the derived type, so the only attribute declarations that need to appear in the derived type definition are those you want to restrict or remove. The legal ways to restrict an attribute declaration are as follows:
• Change the type, as long as the new type is a restriction (or a restriction of a restriction, etc.) of the original type
• Add, change, or remove a default value
• Add a fixed value if none is present in the base type
• Make optional attributes required
• Make optional attributes prohibited
It is not legal in a restriction to
• Change the type to one that is not a restriction of the original type
• Change or remove a fixed value
• Make required attributes optional
• Make required attributes prohibited
Example 13–30 shows a definition of DerivedType
which legally restricts BaseType
. The declarations of attributes a
, b
, c
, d
, e
, f
, and g
represent, respectively, changing the type, adding a default, changing a default, adding a fixed value, keeping the fixed value the same, making an optional attribute required, and prohibiting an optional attribute. Instances of DerivedType
can also have the attribute x
, although it is not mentioned in the definition. This is because all of the attributes of BaseType
are passed down to DerivedType
.
Example 13–30. Legal restrictions of attributes
<xs:complexType name="BaseType">
<xs:attribute name="a" type="xs:integer"/>
<xs:attribute name="b" type="xs:string"/>
<xs:attribute name="c" type="xs:string" default="c"/>
<xs:attribute name="d" type="xs:string"/>
<xs:attribute name="e" type="xs:string" fixed="e"/>
<xs:attribute name="f" type="xs:string"/>
<xs:attribute name="g" type="xs:string"/>
<xs:attribute name="x" type="xs:string"/>
</xs:complexType>
<xs:complexType name="DerivedType">
<xs:complexContent>
<xs:restriction base="BaseType">
<xs:attribute name="a" type="xs:positiveInteger"/>
<xs:attribute name="b" type="xs:string" default="b"/>
<xs:attribute name="c" type="xs:string" default="c2"/>
<xs:attribute name="d" type="xs:string" fixed="d"/>
<xs:attribute name="e" type="xs:string" fixed="e"/>
<xs:attribute name="f" type="xs:string" use="required"/>
<xs:attribute name="g" type="xs:string" use="prohibited"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
Example 13–31 shows a definition of IllegalDerivedType
, which illegally restricts the complex type BaseType2
. Attribute h
is illegal because decimal
is not a restriction of integer
. Attribute i
is illegal because the fixed value is changed. Attribute j
is illegal because the fixed value is removed and replaced by a default value. Attribute k
is illegal because a required attribute is made optional. Attribute l
is illegal because a required attribute is made prohibited. Attributes pref:l
and m
are illegal because they do not appear in the definition of BaseType2
.
Example 13–31. Illegal attribute restrictions
<xs:complexType name="BaseType2">
<xs:attribute name="h" type="xs:integer"/>
<xs:attribute name="i" type="xs:string" fixed="i"/>
<xs:attribute name="j" type="xs:string" fixed="j"/>
<xs:attribute name="k" type="xs:string" use="required"/>
<xs:attribute name="l" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="IllegalDerivedType">
<xs:complexContent>
<xs:restriction base="BaseType2">
<xs:attribute name="h" type="xs:decimal"/>
<xs:attribute name="i" type="xs:string" fixed="i2"/>
<xs:attribute name="j" type="xs:string" default="j"/>
<xs:attribute name="k" type="xs:string"/>
<xs:attribute name="l" type="xs:string" use="prohibited"/>
<xs:attribute ref="pref:l"/>
<xs:attribute name="m" type="xs:string"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
Unlike attribute declarations, attribute wildcards are not automatically passed down from the base type to the restricted type. If you want to use an attribute wildcard for the restricted type, you must specify it inside the restriction
element.
When an attribute wildcard is specified in a restriction, that wildcard becomes the effective wildcard of the type, overriding any attribute wildcards of the base type or its ancestors. However, if any ancestor has an attribute wildcard, the namespace constraint of the new wildcard must be a subset of the ancestor wildcard’s namespace constraint. Table 13–9 shows the legal subsets of namespace constraints.
Table 13–9. Wildcard namespace subsets
Example 13–32 shows a definition of DerivedType
that restricts BaseType
. Both DerivedType
and BaseType
have attribute wildcards specified, with different values for processContents
and namespace
. This definition is legal because DerivedType
’s wildcard is a subset of BaseType
’s wildcard.
Example 13–32. Restricting an attribute wildcard
<xs:complexType name="BaseType">
<xs:anyAttribute processContents="lax" namespace="##any"/>
</xs:complexType>
<xs:complexType name="DerivedType">
<xs:complexContent>
<xs:restriction base="BaseType">
<xs:anyAttribute processContents="strict"
namespace="##targetNamespace
http://www.w3.org/1999/xhtml"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
It is also possible to restrict an attribute wildcard by replacing it with declarations for attributes that are valid according to that wildcard. This is illustrated in Example 13–33.
Example 13–33. Replacing an attribute wildcard with attributes
<xs:complexType name="BaseType">
<xs:anyAttribute processContents="lax" namespace="##any"/>
</xs:complexType>
<xs:complexType name="DerivedType">
<xs:complexContent>
<xs:restriction base="BaseType">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="name" type="xs:string"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
Sometimes it is useful to define complex types in your schema that are restrictions of base types defined in another target namespace. It may be that you are embedding elements from another XML vocabulary in your elements, and you only want to allow a restricted subset of the other vocabulary. Example 13–34 shows this case where the base type, ProductType
, is in a schema document with http://datypic.com/prod as the target namespace. RestrictedProductType
is a derived type, but it is defined in a schema document whose target namespace is http://datypic.com/ord.
This example shows a legal restriction because the complex type contains references to global element declarations. All of the element names in the restricted type are still in the http://datypic.com/prod namespace, as evidenced by the use of the prod
prefix.
Example 13–34. Restricting a type from another namespace with global declarations
prod.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://datypic.com/prod"
xmlns:prod="http://datypic.com/prod"
elementFormDefault="qualified"
attributeFormDefault="qualified">
<xs:complexType name="ProductType">
<xs:sequence>
<xs:element ref="prod:number"/>
<xs:element ref="prod:name"/>
<xs:element ref="prod:size" minOccurs="0"/>
</xs:sequence>
<xs:attribute ref="prod:dept"/>
</xs:complexType>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="size" type="xs:integer"/>
<xs:attribute name="dept" type="xs:string"/>
</xs:schema>
ord.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://datypic.com/ord"
xmlns:prod="http://datypic.com/prod">
<xs:import namespace="http://datypic.com/prod"
schemaLocation="prod.xsd"/>
<xs:complexType name="RestrictedProductType">
<xs:complexContent>
<xs:restriction base="prod:ProductType">
<xs:sequence>
<xs:element ref="prod:number"/>
<xs:element ref="prod:name"/>
</xs:sequence>
<xs:attribute ref="prod:dept" use="required"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
A problem arises, however, if local element declarations are used and they are qualified with a namespace name (either via a form
attribute on the element declaration, or an elementFormDefault
attribute on the schema). In that case, the name
attribute is used instead of ref
, and it is not legal to use a namespace prefix in the name
attribute; all of the values of name
take on the target namespace of the schema document. If Example 13–34 were modified to use local element declarations, the elements in RestrictedProductType
would take on the http://datypic.com/ord namespace, and no longer be a valid restriction of the base type since the element names have changed. The same problem arises for attributes as well as elements, but this occurs less frequently since qualified local attribute declarations are less common.
In version 1.0, this problem is typically avoided by creating a new schema document in the http://datypic.com/prod namespace whose sole purpose is to restrict the original schema document. That new schema document is the one that is imported into the http://datypic.com/ord schema document, which can then reference the restricted types.
Starting in version 1.1, it is possible to restrict a type that has a different target namespace, even if it uses qualified local declarations. This is addressed by the use of a targetNamespace
attribute, which can appear on a local element declaration or local attribute declaration.
This is shown in Example 13–35, which is similar to Example 13–34 but with local declarations instead of global ones. The targetNamespace
attribute is used on the two element declarations and one attribute declaration in the restricted type to indicate that these names still refer to the http://datypic.com/prod namespace.
Example 13–35. Using targetNamespace on element and attribute declarations
prod.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://datypic.com/prod"
elementFormDefault="qualified"
attributeFormDefault="qualified">
<xs:complexType name="ProductType">
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="size" type="xs:integer" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="dept" type="xs:string"/>
</xs:complexType>
</xs:schema>
ord.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://datypic.com/ord"
xmlns:prod="http://datypic.com/prod"
elementFormDefault="qualified"
attributeFormDefault="qualified">
<xs:import namespace="http://datypic.com/prod"
schemaLocation="prod.xsd"/>
<xs:complexType name="RestrictedProductType">
<xs:complexContent>
<xs:restriction base="prod:ProductType">
<xs:sequence>
<xs:element name="number" type="xs:string"
targetNamespace="http://datypic.com/prod"/>
<xs:element name="name" type="xs:string"
targetNamespace="http://datypic.com/prod"/>
</xs:sequence>
<xs:attribute name="dept" type="xs:string" use="required"
targetNamespace="http://datypic.com/prod"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Without the targetNamespace
attributes, this example would not be a legal restriction because it would be trying to change the namespaces of the elements and the attribute from http://datypic.com/prod to http://datypic.com/ord.
Note that this technique is only allowed when restricting a type from another namespace. It is not possible to use the targetNamespace
attribute generally to declare elements and attributes in a target namespace other than that of the schema document.
One of the elegant features of derived types is that they can substitute for their ancestor types in instances. In an instance, an element declared to be of one type can actually have any type that either extends or restricts it. Suppose we have a section of a purchase order that lists products of various kinds. We want repeating product
elements, but we also want to allow different content models for each kind of product. For example, a shirt may have a color and a size, in addition to the normal product information.
Example 13–36 shows a definition of ShirtType
that extends ProductType
. It adds the children size
and color
to the end of the content model.
<xs:complexType name="ProductType">
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="product" type="ProductType"/>
<xs:complexType name="ShirtType">
<xs:complexContent>
<xs:extension base="ProductType">
<xs:choice maxOccurs="unbounded">
<xs:element name="size" type="xs:integer"/>
<xs:element name="color" type="xs:string"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Example 13–37 shows a valid instance of product
. Instead of ProductType
, it has the type ShirtType
which allows it to contain the color
element. It uses the xsi:type
attribute to indicate the type substitution. We could define an additional type for every kind of product, each with a different content model.
Example 13–37. Substitution of ShirtType for ProductType
<items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<product xsi:type="ShirtType">
<number>557</number>
<name>Short-Sleeved Linen Blouse</name>
<color>blue</color>
</product>
<!--...-->
</items>
The xsi:type
attribute is part of the XML Schema Instance Namespace, which must be declared in the instance. This attribute does not, however, need to be declared in the type definition for product
; a schema processor recognizes xsi:type
as a special attribute that may appear on any element.
Type derivation is a powerful tool, but in some cases, you may want to control the creation or substitution of derived types. Three properties of complex types control their derivation:
• The final
property limits the definition of derived types in schemas.
• The block
property limits the substitution of derived types in instances.
• The abstract
property forces the definition of derived types.
This section describes each of these three properties in detail.
You may want to prevent the derivation of other complex types from your type. This is accomplished using the final
attribute, which may have one of the following values:
• #all
prevents any other types from extending or restricting your type.
• extension
prevents any other types from extending your type.
• restriction
prevents any other types from restricting your type.
• extension restriction
and restriction extension
have the same effect as #all
.
• ""
(an empty string) means that there are no restrictions. This value is useful for overriding the value of finalDefault
, as described below.
• If no final
attribute is specified, it takes its value from the finalDefault
attribute of the schema
element.1 If neither final
nor finalDefault
is specified, there are no restrictions on derivation of that complex type.
Example 13–38 shows the definition of a complex type that cannot be restricted or extended by any other type.
Example 13–38. Preventing derivation
<xs:complexType name="ProductType" final="#all">
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
As we saw in Section 13.6 on p. 341, derived types may substitute for their ancestor types in an instance. While this is a valuable feature, there are times when you only want to allow the original type to be used. This is accomplished using the block
attribute, which may have one of the following values:
• #all
prevents any derived types from substituting for your type in instances.
• extension
prevents any extensions of your type from substituting for your type in instances.
• restriction
prevents any restrictions of your type from substituting for your type in instances.
• extension restriction
and restriction extension
have the same effect as #all
.
• ""
(an empty string) means that there are no restrictions. This value is useful for overriding the value of blockDefault
, as described below.
• If no block
attribute is specified, it takes its value from the blockDefault
attribute of the schema
element. If neither block
nor blockDefault
is specified, there are no restrictions.
Example 13–39 shows a definition of ProductType
that does not allow extensions of the type to be used in its place.
Example 13–39. Preventing substitution of derived types
<xs:complexType name="ProductType" block="extension">
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="product" type="ProductType"/>
<xs:complexType name="ShirtType">
<xs:complexContent>
<xs:extension base="ProductType">
<xs:choice maxOccurs="unbounded">
<xs:element name="size" type="xs:integer"/>
<xs:element name="color" type="xs:string"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="shirt" type="ShirtType"/>
The definition of ShirtType
in this example is completely legal. The block
attribute does not prohibit extensions of ProductType
, just the substitution of the extensions in place of the original type in the instance. Example 13–40 shows an illegal instance where the element product
is attempting to substitute ShirtType
for ProductType
. This example would have been legal if the block
attribute had not been used.
Example 13–40. Illegal substitution of ShirtType
<product xsi:type="ShirtType">
<number>557</number>
<name>Short-Sleeved Linen Blouse</name>
<color>blue</color>
</product>
You can also block type substitution for an element declaration that uses the type, rather than the type itself. An element
element can also have the block
attribute, with the same valid values as for complexType
.1 If, in Example 13–39, the block="extension"
attribute had appeared in the product
element declaration rather than in the ProductType
definition, the effect would have been the same as far as the product
instance elements are concerned. Other elements using ProductType
would then be free to substitute derived types.
Abstract complex types are types that cannot be used in instances. They exist solely as placeholders for their derived types. Example 13–41 shows our ProductType
example as an abstract type.
Example 13–41. An abstract type
<xs:complexType name="ProductType" abstract="true">
<xs:sequence>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="product" type="ProductType"/>
<xs:complexType name="ShirtType">
<xs:complexContent>
<xs:extension base="ProductType">
<xs:choice maxOccurs="unbounded">
<xs:element name="size" type="xs:integer"/>
<xs:element name="color" type="xs:string"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="shirt" type="ShirtType"/>
Note that product
is declared to be of the type ProductType
. This is legal, but if a product
element appears in an instance, it must use the xsi:type
attribute to indicate a type that is derived from ProductType
, as shown in Example 13–42.
Example 13–42. Legal instances of product and shirt
<product xsi:type="ShirtType">
<number>557</number>
<name>Short-Sleeved Linen Blouse</name>
<color>blue</color>
</product>
<shirt>
<number>557</number>
<name>Short-Sleeved Linen Blouse</name>
<color>blue</color>
</shirt>
Example 13–43 shows two illegal product
elements that attempt to use the type ProductType
.
Example 13–43. Illegal uses of the abstract ProductType
<product>
<number>557</number>
<name>Short-Sleeved Linen Blouse</name>
</product>
<product xsi:type="ProductType">
<number>557</number>
<name>Short-Sleeved Linen Blouse</name>
</product>