12.2. Controlling Derivations
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
220.127.116.11. Block attribute
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.
TIP: 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, "Complex Types".
18.104.22.168. Final elements
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.
22.214.171.124. Abstract elements
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).
12.2.3. Complex Types
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.
126.96.36.199. Blocking complex types
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.
Figure 12-1. Block attribute on elements and complex type definitions
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.
188.8.131.52. Final 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.
184.108.40.206. Abstract complex types
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.
12.2.4. Simple Types
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, "Creating Simple Datatypes").
12.2.5. Other Components and Redefinitions
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.
TIP: 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.
Copyright © 2002 O'Reilly & Associates. All rights reserved.