It’s time to come back to the features already discussed—and to introduce new ones—to explain how to control the usage of the derivations of the different compositors. Basically, these features are attributes that allow you to block further derivation or, on the contrary, allow you to require derivations, but their granularity varies depending on the compositor being used.
There are no substitution groups for attributes and no mechanism to derive them or define their types in instance documents. This also means no features are needed to control their derivation. Actually, to be completely accurate, we need to note that it is possible to indirectly derive attributes through a derivation by restriction of their parent elements or redefinitions of attribute groups.
When speaking of a xs:element
, we need to differentiate between global
definitions and local definitions or references that behave
differently in regard to derivation. Therefore, derivation control is
maintained as shown in Table 12-2.
Table 12-2. Controls on element derivation
Attribute |
Global element |
Local element definition |
Element reference |
---|---|---|---|
block |
Yes |
Yes |
No |
abstract |
Yes |
No |
No |
final |
Yes |
No |
No |
The
block
attribute
controls type substitution in the instance
documents through the xsi:type
attribute and substitution groups. This
single attribute holds a whitespace-separated list of tokens—
of “restriction,”
“extension,” and
“substitution”—or the
special value #all
(which means all three values
together and the attribute’s default value can be
defined through the
blockDefault
attribute of the
xs:schema
document element).
The first two values (restriction and extension) control any
substitution through xsi:type
or substitution
groups, and block the substitution by datatypes that are derived by
restriction or extension from the datatype defined in the element
declaration. The third (substitution) is specific to the substitution
groups, and defines if an element from the substitution group (for
which the element is the head) is allowed. Since only global elements
can participate in a substitution group, the last value is clearly
meaningful for global definitions only.
The fact that the block
attribute is used both for
type substitution and for substitution groups can be misleading,
especially with the values restriction and extension, which act on
both aspects. A simple example makes this more concrete.
Let’s say that we have a complex type definition
(personType
) describing a person as having a name,
a mandatory birth date, and optional death date and qualification:
<xs:complexType name="personType"> <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:attribute ref="id"/> </xs:complexType>
We can also derive by extension from this complex type a datatype that describes an author as a person with a list of books:
<xs:complexType name="authorType"> <xs:complexContent> <xs:extension base="personType"> <xs:sequence> <xs:element name="book" type="xs:token" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
We can derive by restriction a datatype that describes a character as a person with no death date and a mandatory qualification:
<xs:complexType name="characterType"> <xs:complexContent> <xs:restriction base="personType"> <xs:sequence> <xs:element ref="name"/> <xs:element ref="born"/> <xs:element ref="qualification"/> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType>
The first purpose of block
attributes in element
definitions is to control the type substitution through
xsi:type
, which controls substitutions in the
instance documents such as the following (if the
person
element is defined as having a type
personType
):
<person xsi:type="authorType" id="CMS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <name> Charles M Schulz </name> <born> 1922-11-26 </born> <dead> 2000-02-12 </dead> <book> Being a Dog Is a Full-Time Job </book> </person> <person xsi:type="characterType" id="Snoopy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <name> Snoopy </name> <born> 1950-10-04 </born> <qualification> extroverted beagle </qualification> </person>
The first substitution uses authorType
, which is
derived by extension from personType
, and can be
blocked by specifying a block
attribute including
the value extension
. The second one uses
characterType
, which is derived by restriction
from personType
and can be blocked by specifying a
block
attribute including the value
restriction
. Both can be blocked together by
specifying a block attribute with the value
#all
.
This example shows that the impact of both derivation types on the
applications is very different. A type substitution by restriction
has virtually no impact on the applications, since the content model
matching the restricted type must also match the original type.
Alternatively, a type substitution by extension allows content models
not allowed by the original type (such as the addition of the
book
element in the previous example), and the
risk of breaking applications that do not expect these additions is
higher. Thus, a conservative attitude might be to include
extension
in the default values of
block
in your schemas.
That being said, we’ve seen only one side of the
block
attribute. It serves a second, different,
yet not independent, purpose and also restricts the usage of
substitution groups. To illustrate this purpose,
let’s define three different element members of a
substitution group whose head is person
. There is
also a fourth element member, which is just a synonym for the element
person and has the same type:
<xs:element name="person" type="personType"/> <xs:element name="author" type="authorType" substitutionGroup="person"/> <xs:element name="character" type="characterType" substitutionGroup="person"/> <xs:element name="human" type="personType" substitutionGroup="person"/>
After defining this substitution group and without blocking anything,
we allow not only block
and the type substitutions
seen above, but also element substitutions, such as:
<author id="CMS"> <name> Charles M Schulz </name> <born> 1922-11-26 </born> <dead> 2000-02-12 </dead> <book> Being a Dog Is a Full-Time Job </book> </author> <character id="PP"> <name> Peppermint Patty </name> <born> 1966-08-22 </born> <qualification> bold, brash and tomboyish </qualification> </character> <human id="CMS."> <name> Charles M Schulz </name> <born> 1922-11-26 </born> <dead> 2000-02-12 </dead> </human>
The first substitution is by an element of the substitution group
whose type is derived by extension from the head. It can be blocked
by specifying a block
attribute including the
value extension
. The second one is a substitution
by an element of the substitution group whose type is derived by
restriction from the head. It can be blocked by specifying a
block
attribute including the value
restriction
. Those two are similar to the two
substitutions given as examples for the type substitutions, with the
difference that the element name is now used to differentiate the
type instead of the xsi:type
attribute. The third
substitution is new, since the type is the same as the type of the
head, and it is blocked only by specifying a block
attribute that includes the value substitution
.
Note that including substitution
in a
block
attribute blocks any element substitution,
while stating that not all the combinations are possible to express.
To block everything, you would define author
as:
<xs:element name="author" type="authorType" block="#all"/>
I don’t want to leave you with the impression than you can’t block type substitution without blocking substitution groups. We need to mention that type substitution can also be blocked on complex type definitions, which is covered later on in this chapter in Section 12.2.3.
Like block
,
final
has an impact on substitution groups, but
works on a different level: constraining the schema itself while
block
constrains the instance documents.
final
can take a list of
restriction
and extension
or
the special value #all
, and its default value can
be defined using the
finalDefault
attribute of
xs:schema
. However, a
substitution
value is not necessary, since unlike
block
, final
is about
substitution groups, and #all
can block all the
substitutions (and only the substitutions).
final
’s effect is more radical
than block
: while block
blocks
the effects of the usage of substitution groups,
final
prohibits the usage of the element as a head
of a substitution group. If the person
element is
defined with a final
attribute set, it
isn’t possible to use it as head of a substitution
group for either author
,
character
, or both.
The last attribute is
abstract
, which is the opposite of
block
. It prohibits the element from being used
directly in an instance document and must be substituted through a
substitution group. Defining the person element as
abstract
forbids its use in the instance
documents. You must use one of the elements from its substitution
group (such as author
,
character
, or even human
).
The attributes are the same for complex types as they are for
elements, but their meaning is slightly different since one of them
(block
) operates on the substitution of the
elements that use the datatype (as we have seen in the previous
section). The others (final
and
abstract
) work on the derivation of the complex
type itself.
When the
block
attribute is used on complex type
definitions, the type substitutions in the elements defined with this
type are still blocked. The difference is that this time
block
doesn’t act on element
substitutions through substitution groups, but it does act on type
substitutions. These block
attributes can be seen
as electric switches installed in a series, and each of them can
block the derivation in its own
“line,” as shown in Figure 12-1.
For each restriction
and
extension
, the substitutions can first be switched
off for both element and type substitutions by the
block
attribute of the element definition, and
then the type substitutions can be blocked by the
block
attribute of the complex type definition.
The value substitution
in the block attribute of
the element definition acts as a global switch to block all element
substitutions, including a third line, which allows element
substitutions with the same type and cannot be blocked separately.
The default value supplied in the schema element is used at both
levels and may be different for the element and complex type
definitions if they belong to different schemas and have a different
xs:schema
ancestor. The fact that the default
value, when defined in the
xs:schema
ancestor, is applied to both levels
means that it may block the derivation for those to levels (by
“opening” two switches). To
override such a nonempty default value, you need to define a
block
attribute both in the element and in the
complex type definition.
The
final
attribute of complex type
definitions controls whether the type can be derived by restriction
and or extension to create new complex types.
Unlike the block
attribute which is linked with
its counterpart in the element definition, the
final
attribute in a complex type definition
applies only to the complex type itself and, like the
abstract
attribute in the element definition, it
acts at the level of the schema itself and has no impact on the
instance documents.
The abstract
attribute of complex type definitions
works on the instance documents. When an abstract datatype is used to
define elements, the type must be substituted in the instance
documents through a xsi:type
attribute.
We need to insist that abstract
by itself
doesn’t mean that the complex type cannot be used in
a content model. However, if it is used, it must be substituted
through xsi:type
in the instance documents. To
define a complex type that will not be usable in a content model, we
need to use both the final
and
block
attributes; the complex
type’s only use is as a base type for derivations.
Simple types are, in fact, simpler, as
far as controlling their derivation is concerned, since they can only
be final
. Their
final
attribute can take the values
list
, restriction
,
union
, or the special value
#all
, which means the three of them and the
default value are controlled through the
finalDefault
attribute of the schema element used for
elements and complex types.
The fact that simple types cannot be abstract
or
block
ed avoids potential issues when they are used
to define attributes for which these notions are meaningless. When
needed to define elements, a simple content complex type may be
created using the simple type as its base. This complex type can hold
the abstract
and block
attribute.
Even though final
is the only attribute
controlling simple type element derivation available on the
xs:simpleType(global definition)
element, a finer granularity of control may be achieved through the
fixed
attributes available on each of the
facets (discussed in Chapter 5).
Other components, such as attributes and element and attribute
groups, cannot be directly derived. Attributes can’t
be derived at all and groups can only be derived through
redefinitions; therefore, no control is available to control their
derivation. Similarly, the redefinitions of groups through
xs:redefine
escape this feature
and cannot be controlled at all. Although the recommendation is fuzzy
on this aspect, it is safer to consider that the
final
attribute of the complex types applies also
to their redefinitions, which are processed as implicit derivations.
The interpretation of the block
attribute is
subject to multiple interpretations. For the latest opinion of the
W3C XML Schema Working Group, you should refer to the errata for the
specification
at http://www.w3.org/2001/05/xmlschema-errata.