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.
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"/>
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.
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 not 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 kinds 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>
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>