XML Schema provides the ability to define groups of element and attribute declarations that are reusable by many complex types. Named model groups are fragments of content models, and attribute groups are bundles of attribute declarations that are commonly used together. This chapter explains how to define and reference named model groups and attribute groups.
Defining a group and reusing it many times has the advantages of
• Encouraging consistency across schema components
• Allowing the schema author to change multiple content models in only one place
• Making it obvious that certain complex types share similar children or attributes
• In many cases, making the schema less verbose
Named model groups are reusable fragments of content models. For example, if there are many type definitions in your schema that specify a description
, optionally followed by a comment
, you could define a group that represents this content model fragment. The group could then be used by many complex type definitions. Named model groups cannot contain attribute declarations; that is the purpose of attribute groups, which are described in Section 15.3 on p. 392.
A note on terminology: XML Schema formally uses the term “model group definition” for group
elements, and “model group” for all
, choice
, and sequence
groups. In this book, group
elements are referred to as “named model groups” to reduce confusion associated with the two similar terms.
Named model groups are represented by group
elements whose syntax is shown in Table 15–1. Named model groups are required to have a name
, and that name must be unique among all the named model groups in the schema. Named model groups are always defined globally, meaning that their parent is always schema
.1
Table 15–1. XSD Syntax: named model group definition
Named model groups may contain any content model. However, a group
cannot contain an element
directly. Instead, group
must have one and only one model group (choice
, sequence
, or all
) as a child. There is an additional constraint that this one model group child cannot have occurrence constraints (minOccurs
and maxOccurs
) like other model groups. If you wish to indicate that the contents of the group appear multiple times, you may put occurrence constraints on the group reference, as described in Section 15.2.2.1 on p. 388.
Example 15–1 shows the definition of a named model group that contains a description
optionally followed by a comment
. Note that the group
has one child, a sequence
, which has no occurrence constraints on it.
Example 15–1. Named model group with local element declarations
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:group name="DescriptionGroup">
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="comment" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:group>
</xs:schema>
In Example 15–1, the element declarations are local in the group
, as evidenced by the appearance of a name
attribute instead of a ref
attribute. It is also possible to use global element declarations, and then reference them from the named model group, as shown in Example 15–2.
Note that the type
attribute is now in the global element declaration, while minOccurs
stays in the reference to the element declaration. This is the same syntax as that used in complex types to reference global element declarations. In fact, when a complex type references a named model group, it is as if the schema author cut and pasted the contents of the group
element into the complex type definition. All local element declarations in the group become local to that complex type.
Example 15–2. Named model group with element references
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="description" type="xs:string"/>
<xs:element name="comment" type="xs:string"/>
<xs:group name="DescriptionGroup">
<xs:sequence>
<xs:element ref="description"/>
<xs:element ref="comment" minOccurs="0"/>
</xs:sequence>
</xs:group>
</xs:schema>
Whether to use local element declarations in the group depends on whether you want these element declarations to be local to the complex type. For a complete discussion of global versus local element declarations, see Section 6.1.3 on p. 95.
Named model groups may be referenced in complex types and in other groups. Since they are named global schema components, they may be referenced not only from within the same schema document, but also from other schema documents.
The syntax to reference a named model group is shown in Table 15–2. Named model groups are referenced through the ref
attribute, just like other global schema components.
Table 15–2. XSD Syntax: named model group reference
Example 15–3 shows the definition of the complex type PurchaseOrderType
that references DescriptionGroup
.
Example 15–3. Referencing a group from a complex type definition
<xs:complexType name="PurchaseOrderType">
<xs:sequence>
<xs:group ref="DescriptionGroup" minOccurs="0"/>
<xs:element ref="items"/>
<!--...-->
</xs:sequence>
</xs:complexType>
Note that when referencing a group, minOccurs
and maxOccurs
may be specified to indicate how many times the contents of the group may appear. If minOccurs
and maxOccurs
are not specified, the default for both values is 1
. The value for minOccurs
must be less than or equal to the value for maxOccurs
. This means that if a minOccurs
value is specified that is more than 1, maxOccurs
must also appear, with a value greater than or equal to minOccurs
.
To illustrate how named model group references are handled, Example 15–4 shows a content model equivalent to Example 15–3 (assuming it was referencing DescriptionGroup
from Example 15–1) but without a named model group being used. Note that the minOccurs="0"
constraint that appeared in the group reference now appears in the sequence
tag.
Example 15–4. Equivalent content model without a named model group reference
<xs:complexType name="PurchaseOrderType">
<xs:sequence>
<xs:sequence minOccurs="0">
<xs:element name="description" type="xs:string"/>
<xs:element name="comment" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:element ref="items"/>
<!--...-->
</xs:sequence>
</xs:complexType>
In Example 15–3, the group is referenced within a sequence
group. Named model groups may be referenced anywhere in the content model, and multiple named model group references (even to the same group) are allowed.
A named model group may also be referenced at the top level of a complexType
, if the group contains the entire content model of the type. A complex type may only directly contain either one named model group (group
) or one model group (all
, sequence
, or choice
). Example 15–5 shows the definition of DescriptionType
that references DescriptionGroup
at the top level.
Example 15–5. Group reference at the top level of the content model
<xs:complexType name="DescriptionType">
<xs:group ref="DescriptionGroup"/>
<xs:attribute ref="xml:lang"/>
</xs:complexType>
An all
group may appear in named model groups, but the additional constraints on all
groups still apply. Example 15–6 shows a legal use of an all
group within a named model group. In version 1.0, an all
group may only contain element declarations or references, not other groups.
Example 15–6. Group with an all model group
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:group name="DescriptionGroup">
<xs:all>
<xs:element name="description" type="xs:string"/>
<xs:element name="comment" type="xs:string" minOccurs="0"/>
</xs:all>
</xs:group>
</xs:schema>
In version 1.0, since all
groups can only appear at the top level of a complex type, the only way to reference a named model group that contains an all
group is at the top level, as shown in Example 15–5. Version 1.1 has relaxed this constraint, and it is possible to reference a named model group that contains all
from another all
group, provided that minOccurs
and maxOccurs
are 1
on the group reference. However, it is still not legal to reference such a group from within a choice
or sequence
.
Named model groups may reference other named model groups. This is shown in Example 15–7, where ProductPropertyGroup
references DescriptionGroup
.
Example 15–7. Group reference from a group
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:group name="ProductPropertyGroup">
<xs:sequence>
<xs:group ref="DescriptionGroup"/>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:group>
<xs:group name="DescriptionGroup">
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="comment" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:group>
</xs:schema>
The group references cannot be circular. That is, group a
cannot reference itself, and group a
cannot reference group b
if the latter references group a
, or another group c
which references a
, and so on. In addition, groups may only contain references to other groups; they cannot actually contain the definitions of groups, since all groups are defined globally.
Attribute groups are used to represent groups of related attributes that appear in many different complex types. For example, if the attributes id
, name
, and version
are used in multiple complex types in your schema, it may be useful to define an attribute group that contains declarations for these three attributes, and then reference the attribute group in various complex type definitions.
Attribute groups are represented by attributeGroup
elements, whose syntax is shown in Table 15–3. Attribute groups are required to have a name
, and that name must be unique among all the attribute groups in the schema. Attribute groups are always defined globally, meaning that their parent is always schema
.1
Table 15–3. XSD Syntax: attribute group definition
Attribute groups may contain any number of attribute declarations and references to other attribute groups, plus one optional attribute wildcard. An attribute group cannot contain more than one attribute declaration with the same qualified name. In version 1.0, there is an additional constraint that an attribute group cannot contain more than one attribute declaration of type ID
.
For example, if many complex type definitions will use the attributes id
and version
, you could define an attribute group that contains declarations for these two attributes, as shown in Example 15–8.
Example 15–8. Attribute group with local attribute declarations
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:attributeGroup name="IdentifierGroup">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="version" type="xs:decimal"/>
</xs:attributeGroup>
</xs:schema>
In Example 15–8, the attributes are declared locally in the attribute group, as evidenced by the appearance of a name
attribute instead of a ref
attribute. It is also possible to use global attribute declarations and reference them from the attribute group, as shown in Example 15–9.
Example 15–9. Attribute group with attribute references
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:attribute name="id" type="xs:ID"/>
<xs:attribute name="version" type="xs:decimal"/>
<xs:attributeGroup name="IdentifierGroup">
<xs:attribute ref="id" use="required"/>
<xs:attribute ref="version"/>
</xs:attributeGroup>
</xs:schema>
Note that the type
attribute is now in the global attribute declaration, while the use
attribute stays in the reference to the attribute declaration. This is the same way that complex types reference global attribute declarations. In fact, when a complex type references an attribute group, it is as if the schema author cut and pasted the contents of the attribute group definition into the complex type definition. All attributes that are declared locally in the attribute group become local to that complex type.
Whether to declare attributes locally in the attribute group depends on whether you want the attributes to be local to the complex type. For a complete discussion of global versus local attribute declarations, see Section 7.2.3 on p. 119.
Attribute groups may reference other attribute groups, as described in the next section. Attribute groups may also contain one attribute wildcard at the very end, as shown in Example 15–10. Attribute groups are limited to one attribute wildcard because a complex type cannot contain more than one attribute wildcard. See Section 12.7.3 on p. 298 for more information.
Example 15–10. Attribute group with a wildcard
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:attributeGroup name="IdentifierGroup">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="version" type="xs:decimal"/>
<xs:anyAttribute namespace="##other"/>
</xs:attributeGroup>
</xs:schema>
Attribute groups may be referenced in complex types and in other attribute groups. Since they are named global schema components, they may be referenced not only from within the same schema document, but also from other schema documents.
The syntax to reference an attribute group is shown in Table 15–4. Attribute groups are referenced using the ref
attribute, just like other global schema components.
Table 15–4. XSD Syntax: attribute group reference
Example 15–11 shows the definition of the complex type ProductType
that references the attribute group IdentifierGroup
.
Example 15–11. Referencing an attribute group from a complex type definition
<xs:complexType name="ProductType">
<xs:sequence>
<!--...-->
</xs:sequence>
<xs:attributeGroup ref="IdentifierGroup"/>
<xs:attribute name="effDate" type="xs:date"/>
</xs:complexType>
As shown in the example, references to attribute groups must appear after the content model (a sequence
group in this example). They may appear before, after, or in between attribute declarations. The order of attribute groups (and attributes) in a complex type is insignificant.
To illustrate how XML Schema handles attribute group references, Example 15–12 shows a complex type definition that is equivalent to Example 15–11 (assuming it was referencing IdentifierGroup
from Example 15–8) but without an attribute group being used. It is as if the schema author cut and pasted the attribute declarations from the attribute group.
Example 15–12. Equivalent complex type without an attribute group
<xs:complexType name="ProductType">
<!--...-->
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="version" type="xs:decimal"/>
<xs:attribute name="effDate" type="xs:date"/>
</xs:complexType>
It is illegal to declare two attributes with the same qualified name in the same complex type. When using attribute groups, be sure that the referenced attribute group does not declare an attribute that is already declared directly in your complex type definition. Also, when referencing more than one attribute group in a complex type definition, be sure that the two attribute groups do not contain attribute declarations with identical names.
In Example 15–13, each of the attribute groups IdentifierGroup
and VersionGroup
contain a declaration of version
, and the definition of ProductType
references both attribute groups. This results in an illegal duplication of the version
attribute for ProductType
.
Example 15–13. Illegal duplication of attributes
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:attributeGroup name="IdentifierGroup">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="version" type="xs:decimal"/>
</xs:attributeGroup>
<xs:attributeGroup name="VersionGroup">
<xs:attribute name="version" type="xs:decimal"/>
</xs:attributeGroup>
<xs:complexType name="ProductType">
<xs:attributeGroup ref="IdentifierGroup"/>
<xs:attributeGroup ref="VersionGroup"/>
</xs:complexType>
</xs:schema>
Each attribute group definition may only contain one attribute wildcard. However, it is possible for a complex type definition to reference two attribute groups, each of which contains an attribute wildcard. The complex type definition may also have a “local” wildcard, that is, an anyAttribute
child.
In such a case, an effective attribute wildcard is determined by taking the intersection of the constraints of all of the wildcards, including the local wildcard and any that were included from attribute groups. A simple rule of thumb is that any replacement attribute must conform to all of the attribute wildcards for that complex type.
The value of processContents
for this effective wildcard is the value of processContents
for the local wildcard, if it is present. If it is not, the schema processor takes the value of processContents
from the first attribute wildcard among the attributeGroup
children.
For more information on attribute wildcards, see Section 12.7.3 on p. 298.
Definitions of attribute groups may also reference other attribute groups. This is shown in Example 15–14, where HeaderGroup
references IdentifierGroup
. Attribute groups may only contain references to other attribute groups; they cannot actually contain the definitions of attribute groups, since all attribute groups are defined globally.
Example 15–14. Attribute group referencing an attribute group
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:attributeGroup name="HeaderGroup">
<xs:attributeGroup ref="IdentifierGroup"/>
<xs:attribute ref="xml:lang"/>
</xs:attributeGroup>
<xs:attributeGroup name="IdentifierGroup">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="version" type="xs:decimal"/>
</xs:attributeGroup>
</xs:schema>
In version 1.0, attribute group references cannot be circular. That is, HeaderGroup
cannot reference IdentifierGroup
if IdentifierGroup
also has a reference back to HeaderGroup
(either directly or through a chain of attribute group references). In version 1.1, circular references are permitted, and the effect is that all of the attributes of both HeaderGroup
and IdentifierGroup
are included.
In version 1.1, you can indicate that an attribute group is the default attribute group by specifying its name in the defaultAttributes
attribute on the schema
element. If such a default attribute group is defined, the attributes declared in that group will automatically be allowed for every complex type in the schema document, unless you specifically disallow it.
Example 15–15 shows a schema that defines a default attribute group. The defaultAttributes
attribute on the schema
names prod:IdentifierGroup
as the default attribute group. It uses the prod
prefix because the namespace must be taken into account when referencing any other schema component.
Example 15–15. Default attribute group
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:prod="http://datypic.com/prod"
targetNamespace="http://datypic.com/prod"
defaultAttributes="prod:IdentifierGroup">
<xs:attributeGroup name="IdentifierGroup">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="version" type="xs:decimal"/>
</xs:attributeGroup>
<xs:complexType name="ProductType">
<xs:sequence>
<!--...-->
</xs:sequence>
<xs:attribute name="dept" type="xs:string"/>
</xs:complexType>
<xs:complexType name="CatalogType" defaultAttributesApply="false">
<xs:sequence>
<!--...-->
</xs:sequence>
<xs:attribute name="catalogNumber" type="xs:integer"/>
</xs:complexType>
</xs:schema>
The effect of declaring the default attribute group is as if ProductType
had included a reference to the attribute group; id
and version
attributes can appear on instances of this type. ProductType
can also contain other attribute declarations or attribute group references. CatalogType
, however, does not use the default attribute group, because it specifically disallows it using the attribute defaultAttributesApply="false"
.
Like most global components, named groups take on the target namespace of the schema document, so they need to be referenced with their qualified names. Example 15–16 works because the target namespace is the same as the default namespace, so that when the groups are referenced using the ref
attribute, it is looking for their names in the target namespace.
Example 15–16. Named groups with a target namespace
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
xmlns="http://datypic.com/prod"
targetNamespace="http://datypic.com/prod">
<xs:group name="DescriptionGroup">
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="comment" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:group>
<xs:attributeGroup name="IdentifierGroup">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="version" type="xs:decimal"/>
<xs:anyAttribute namespace="##other"/>
</xs:attributeGroup>
<xs:complexType name="PurchaseOrderType">
<xs:sequence>
<xs:group ref="DescriptionGroup" minOccurs="0"/>
<xs:element ref="items"/>
<!--...-->
</xs:sequence>
<xs:attributeGroup ref="IdentifierGroup"/>
</xs:complexType>
</xs:schema>
When referencing named groups that are defined in a different namespace, the names need to be appropriately prefixed. This is shown in Example 15–17 where the values of the ref
attribute use prefixed names prod:DescriptionGroup
and prod:IdentifierGroup
because that namespace is not the default in ord.xsd
.
Example 15–17. Named groups across namespaces
ord.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
xmlns="http://datypic.com/ord"
xmlns:prod="http://datypic.com/prod"
targetNamespace="http://datypic.com/ord">
<xs:import namespace="http://datypic.com/prod"
schemaLocation="prod.xsd"/>
<xs:complexType name="PurchaseOrderType">
<xs:sequence>
<xs:group ref="prod:DescriptionGroup" minOccurs="0"/>
<xs:element ref="items"/>
<!--...-->
</xs:sequence>
<xs:attributeGroup ref="prod:IdentifierGroup"/>
</xs:complexType>
</xs:schema>
prod.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
xmlns="http://datypic.com/prod"
targetNamespace="http://datypic.com/prod">
<xs:group name="DescriptionGroup">
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="comment" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:group>
<xs:attributeGroup name="IdentifierGroup">
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="version" type="xs:decimal"/>
<xs:anyAttribute namespace="##other"/>
</xs:attributeGroup>
</xs:schema>
The locally declared elements have qualified names, that is, they are in a namespace and elementFormDefault
is set to qualified
. Note that the names of those elements declared in prod.xsd
will retain the target namespace of that schema document, http://datypic.com/prod. Being referenced as a group from a schema document with a different target namespace does not change their namespace, even though they are locally declared.
There may be cases where it is unclear when to define a named group and when to use complex type derivation. Complex type derivation, like named groups, serves the purpose of allowing reuse of content models and attributes.
For example, if there are several places in your purchase order where you allow a description
optionally followed by a comment
, you could define a named model group to represent this. You could then reuse this group in the content model of several, possibly dissimilar complex types.
However, it is also possible to represent this differently. You can define a base complex type that has the descriptive element declarations, and several complex types that extend the base type to specify additional children. Example 15–18 illustrates this approach.
The same dilemma can apply to attributes, which can be reused both through attribute groups and through complex type extensions.
Either of these two methods is legal, but each has its advantages and disadvantages. Use a named model group if:
• The fragment you want to reuse does not appear first in some of the types’ content models. This is because extension adds a derived type’s content model after its base type’s content model as if they were in a sequence
group. In the above example, if the descriptive information did not come first, it would have been impossible to use extension.
Example 15–18. Reusing content model fragments through derivation
<xs:complexType name="DescribedType">
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="comment" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PurchaseOrderType">
<xs:complexContent>
<xs:extension base="DescribedType">
<xs:sequence>
<xs:element ref="items"/>
<!--...-->
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="ItemsType">
<xs:complexContent>
<xs:extension base="DescribedType">
<xs:sequence>
<xs:element ref="product" maxOccurs="unbounded"/>
<!--...-->
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
• The types are dissimilar concepts that just happen to share a small content model fragment. It may not be intuitive to derive them from the same base type.
On the other hand, use a complex type derivation if:
• The reusable content model fragments appear at the beginning of the content model.
• The types have mostly the same content model with just a few differing element or attribute declarations.