Chapter 13. Deriving complex types

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.

13.1. Why derive types?

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.”

13.2. Restriction and extension

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.

13.3. Simple content and complex content

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.

13.3.1. simpleContent elements

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

Image

13.3.2. complexContent elements

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

Image

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.

13.4. Complex type extensions

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

Image

13.4.1. Simple content extensions

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

Image

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.

13.4.2. Complex content extensions

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

Image

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>


13.4.2.1. Extending choice groups

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.

image
13.4.2.2. Extending all groups

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>


13.4.2.3. Extending open content

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>


image

13.4.3. Mixed content extensions

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>


13.4.4. Empty content extensions

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>


13.4.5. Attribute extensions

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"/>


13.4.6. Attribute wildcard extensions

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>


13.5. Complex type restrictions

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

Image

13.5.1. Simple content restrictions

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

Image

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>


13.5.2. Complex content restrictions

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

Image

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.

image

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.

image
13.5.2.1 Eliminating meaningless groups

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>

Legal restriction:

<xs:sequence>
  <xs:element name="a"/>
  <xs:element name="b"/>
</xs:sequence>


13.5.2.2 Restricting element declarations

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>


13.5.2.3 Restricting wildcards

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"/>


13.5.2.4 Restricting groups

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>

Illegal restriction:

<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>


image
13.5.2.5 Restricting open content

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.

image

13.5.3. Mixed content restrictions

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>


13.5.4. Empty content restrictions

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>


13.5.5. Attribute restrictions

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>


13.5.6. Attribute wildcard restrictions

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

Image

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>


13.5.7. Restricting types from another namespace

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.

image
13.5.7.1 Using targetNamespace on element and attribute declarations

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.

image

13.6. Type substitution

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.

Example 13–36. A derived type


<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.

13.7. Controlling type derivation and substitution

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.

13.7.1. final: Preventing complex type derivation

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>


13.7.2. block: Blocking substitution of derived types

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>


13.7.3. Blocking type substitution in element declarations

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.

13.7.4. abstract: Forcing derivation

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>


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.150.119