Groups, Keys, and Redefine
R. Alexander Milowski
milowski at sims.berkeley.edu
#1
Re-usable Definitions
In many languages, you can define "macros" that are re-usable bits of syntax.
For documents, you can re-use instances via xinclude.
XML Schema has the same for definitions of types, content model groups, and attribute groups.
#2
Attribute Groups
Attribute groups are a way to group together attribute declarations.
They are used in complex type definitions to add attributes to the type.
You can also build up attribute groups by aggregating other attribute groups.
#3
Attribute Groups - Syntax
They are declared using the xs:attributeGroup element.
You give them a name that you can then refer in element declarations or attribute group definitions.
They can contain some number of xs:attribute or xs:attributeGroup elements.
A declaration:
<xs:attributeGroup name="linkingAttributes"> <xs:attribute name="href" type="xs:anyURI"/> <xs:attribute name="content-type" type="xs:string"/> </xs:attributeGroup>
A reference
<xs:attributeGroup ref="my:linkingAttributes"/>
#4
Attribute Groups - Example - Part 1
XHTML has several sets of common attributes (see XHTML 1.1).
For example, the core attributes:
<xs:attributeGroup name="Core"> <xs:attribute name="class" type="xs:NMTOKENS"/> <xs:attribute name="id" type="xs:ID"/> <xs:attribute name="title" type="xs:string"/> </xs:attributeGroup>
Some attribute groups are just aggregations:
<xs:attributeGroup name="Common"> <xs:attributeGroup ref="xhtml:Core"/> <xs:attributeGroup ref="xhtml:Events"/> <xs:attributeGroup ref="xhtml:I18N"/> <xs:attributeGroup ref="xhtml:Style"/> </xs:attributeGroup>
#5
Attribute Groups - Example - Part 2
A use of this attribute group might be:
<xs:complexType name="BlockInlineContainer" mixed="true"> <xs:sequence> <xs:element name="xhtml:inline"/> </xs:sequence> <xs:attributeGroup ref="xhtml:Common"/> </xs:complexType>
An element declaration for p:
<xs:element name="p" type="xhtml:BlockInlineContainer"/>
Any of the common XHTML attributes are allowed:
<p class="description" xml:lang="us-en" onclick="javascript:go()"> Something fancy happens here... </p>
#6
Using Attribute Groups
Situations where they are useful:
Grouping commonly used attributes (e.g. the events attributes from XHTML).
Grouping definitions so they are always the same.
Reusing an attribute declaration without making the attribute global (an important distinction).
Keep in mind:
This is a schema-side definition.
The instance doesn't look any different than if you had declared the attribute inside some complex type.
#7
Model Groups
A model group is a reusable content model.
It is used inside a complex type definition or another model group definition.
Anything that is a legal content model is allowed inside--including references to other model groups.
#8
Model Group Syntax
You use an xs:group element to define a model group.
You give it a name that you can then refer to using a QName.
The content is just like xs:complexType in that it must start with xs:all, xs:sequence, or xs:choice.
A declaration:
<xs:group name="ListContents"> <xs:sequence> <xs:element name="item" maxOccurs="unbounded"/> </xs:sequence> </xs:group>
A reference:
<xs:group ref="my:ListContents"/>
#9
Model Group Example - Part 1
The schema for XML Schema makes use of model groups.
This group defines top-level elements:
<xs:group name="schemaTop"> <xs:choice> <xs:group ref="xs:redefinable"/> <xs:element ref="xs:element"/> <xs:element ref="xs:attribute"/> <xs:element ref="xs:notation"/> </xs:choice> </xs:group>
which refers to:
<xs:group name="redefinable"> <xs:choice> <xs:element ref="xs:simpleType"/> <xs:element ref="xs:complexType"/> <xs:element ref="xs:group"/> <xs:element ref="xs:attributeGroup"/> </xs:choice> </xs:group>
#10
Model Group Example - Part 2
The schema for XML Schema then uses them to define the 'schema' element.
The snippet of that declaration:
<xs:element name="schema" id="schema"> <xs:complexType> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:sequence> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xs:include"/> <xs:element ref="xs:import"/> <xs:element ref="xs:redefine"/> <xs:element ref="xs:annotation"/> </xs:choice> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:group ref="xs:schemaTop"/> <xs:element ref="xs:annotation" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:sequence> ... </xs:extension> </xs:complexContent> </xs:complexType> </xs:element>
#11
Identity Constraints
You may have element with values (children or attributes) that must be unique within some context.
Other elements may refer to those values.
Ideally, you'd like your schema to describe these constraints so they can be enforced.
This is what XML Schema's keys are used to accomplish.
#12
Kinds of Identity Constraints
Uniqueness constraints: A combination of values is unique within a scope when present.
Key constraints: A uniqueness constraint where the values must be present.
Key references: A reference to some key value.
#13
Selectors
A selector scopes a constraint.
This scoping is specified by an XPath expression.
This XPath is restricted the child axis:
products/product
The selector element is used to specify this XPath:
<xs:selector xpath="description/name"/>
#14
Fields
A field selects a part of an element identified by a selector.
You can have multiple field elements to allow for multi-part constructs.
This field is specified by an XPath expression.
This XPath is restricted the child axis except that the last step can specify an attribute:
@id description/name pricing/@price
The field element is used to specify this XPath:
<xs:field xpath="description/name"/>
#15
XPath Subset
The grammar for selectors:
[1] Selector ::= Path ( '|' Path )* [2] Path ::= ('.//')? Step ( '/' Step )* [3] Step ::= '.' | NameTest [4] NameTest ::= QName | '*' | NCName ':' '*'
The grammar for fields:
[7] Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest )
Keep in mind that the default namespace does not affect XPath expressions--so don't use the default namespace in your schema!!!
#16
Uniqueness Constraints
A uniqueness constraint is specified within the element declaration--not the complex type definition.
A uniqueness constraint can be specified for optional content.
It is specified by the 'unique' element--which has a 'name' attribute and contains a 'selector' and one or more 'field' elements.
A declaration:
<xs:unique name="product-name"> <xs:selector xpath="."/> <xs:field xpath="name"/> </xs:unique>
#17
Uniqueness Example
Rather than using xs:ID, we can duplicate what ID does without restricting the value to xs:NAME.
Suppose we have a description of a date and references to that date in some historical text.
We can make the type xs:date and guarantee that there is only on description for each date:
<xs:element name="description-of-date"> <xs:complexType> <xs:sequence> <xs:element ref="xhtml:p" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="date" type="xs:date" use="required"/> <xs:complexType> <xs:unique name="date-is-unique"> <xs:selector xpath="."/> <xs:field xpath="@date"/> </xs:unique> </xs:element>
#18
Key Constraints
A key constraint is just like a uniqueness constraint.
Except the selector and field specified must exist.
The other big difference is that keys can be referred to within the document.
A key is required to make a reference can be validated.
It is specified by the 'key' element with:
a required 'name' attribute.
One 'selector' child.
One or more 'field' children.
A key declaration example:
<xs:key name="product-name"> <xs:selector xpath="."/> <xs:field xpath="name"/> </xs:key>
#19
Key Example
If we wanted to be able to refer to that date description as described in the uniqueness example, just change it to a key.
This allows other elements in the document to refer to this date value.
The changed declaration:
<xs:element name="description-of-date"> <xs:complexType> <xs:sequence> <xs:element ref="xhtml:p" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="date" type="xs:date" use="required"/> <xs:complexType> <xs:key name="date-key"> <xs:selector xpath="."/> <xs:field xpath="@date"/> </xs:key> </xs:element>
#20
Key References
A key reference defines a set of values that must match some key in the document.
Each field must match, in the same order, to the fields of the refered key.
The 'refer' attribute points to a key via a QName.
A key reference specified by the 'keyref' element with:
a required 'name' attribute.
a required 'refer' attribute that names a matching key.
One 'selector' child.
One or more 'field' children.
A keyref declaration:
<xs:keyref name="product-reference" refer="my:product-name"> <xs:selector xpath="."/> <xs:field xpath="product-used"/> </xs:keyref>
#21
Key Reference Example
Suppose in paragraph text we want to be able to have embedded dates link to date descriptions.
We can add a 'dateref' element that has date content.
We'll enforce that the date content has to have a corresponding 'description-of-date' element.
The 'dateref' declaration:
<xs:element name="dateref" type="xs:date"> <xs:keyref name="date-pointer" refer="my:date-key"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:keyref> </xs:element>
#22
Redefine
You can redefine types, model groups, and attribute groups in XML Schema.
This allows you to declaratively modify a schema for different purposes:
Specialization of types.
Extensions of content models.
Modifications to the type hierarchy.
Redefines allow repurposing of schemata without changing them.
#23
Like an Include
Redefine is like an include in that you point to a schema to include:
<xs:redefine schemaLocation="part.xsd"> ... </xs:redefine>
The difference is that types, model groups, and attribute groups can be redefined.
This definition takes the place of the original definition.
The restriction is that the definition must be a derivation of the original definition.
#24
Redefining Simple Types
You can redefine simple types.
The new definition must be a restriction of the old definition.
This means a strange definition like:
<xs:simpleType name="Sizes"> <xs:restriction base="my:Sizes"> ... </xs:restriction> </xs:simpleType>
It is like a restriction of itself.
The effect is a type derivation and a shifting of all the uses to the derived type.
#25
Redefining Simple Types - Example
In types.xsd:
<xs:simpleType name="Sizes"> <xs:restriction base="xs:postiveIntegers"/> </xs:simpleType> <xs:element name="size" type="my:Sizes"/>
The redefine:
<xs:redefine schemaLocation="types.xsd"> <xs:simpleType name="Sizes"> <xs:restriction base="my:Sizes"> <xs:enumeration value="2"/> <xs:enumeration value="4"/> <xs:enumeration value="6"/> <xs:enumeration value="8"/> <xs:enumeration value="10"/> <xs:enumeration value="12"/> </xs:restriction> </xs:simpleType> </xs:redefine>
The effect is the element 'size' can only have content of '2', '4',...,'12'.
#26
Redefining Complex Types
You can redefine complex types.
The new definition must be a extension or restriction of the old definition.
This means a strange definition like:
<xs:complexType name="Person"> <xs:complexContent> <xs:extension base="my:Person"> ... </xs:extension> </xs:complexContent> </xs:complexType>
Again, the effect is a type derivation and a shifting of all the uses to the derived type.
#27
Redefining Complex Types - Example
In types.xsd:
<xs:complexType name="Person"> <xs:sequence> <xs:element name="name" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:element name="person" type="ns:Person"/>
The redefine:
<xs:redefine schemaLocation="types.xsd"> <xs:complexType name="Person"> <xs:complexContent> <xs:extension base="ns:Person"> <xs:sequence> <xs:element name="address" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> </xs:redefine>
This is now valid:
<person xmlns="http://www.example.org/test"> <name>Alex Milowski</name> <address>San Francisco, CA</address> </person>
#28
Redefining a Model Group
Model group definitions can be redefined to be a superset or subset.
Subsetting either means:
Removing optionality.
Removing optional elements.
Restricting occurrences.
Supersetting means:
You make only one necessary reference to the old group definition.
You add new elements before, after, or before and after the group reference.
#29
Redefining a Model Group - Example
You can use this to make extend a choice group.
In types.xsd:
<xs:group name="top-level"> <xs:choice> <xs:element ref="my:xslt"/> <xs:element ref="my:subtree"/> <xs:element ref="my:wrap"/> <xs:element ref="my:template"/> </xs:choice> </xs:complexType>
The redefine:
<xs:redefine schemaLocation="types.xsd"> <xs:group name="top-level"> <xs:choice> <xs:group ref="my:top-level"/> <xs:element ref="my:route"/> </xs:choice> </xs:redefine>
#30
Redefining an Attribute Group
Attribute group definitions can be redefined to be a superset or subset.
Subsetting either means:
Removing optionality.
Removing optional attributes
Restricting attributes by adding default or fixed values.
Supersetting means:
Make only one necessary reference to the old attribute group.
Add new attribute declarations.
You cannot change the old definitions of the attributes.
#31
Redefining an Attribute Group - Example
You can extend an attribute group for linking to add a content type:
In types.xsd:
<xs:attributeGroup name="linking"> <xs:attribute name="href" type="xs:anyURI" use="required"/> <xs:attribute name="alt" type="xs:string"/> <xs:attribute name="title" type="xs:string"/> </xs:attributeGroup>
The redefine:
<xs:redefine schemaLocation="types.xsd"> <xs:attributeGroup name="linking"> <xs:attributeGroup ref="my:linking"/> <xs:attribute name="content-type" type="xs:string"/> </xs:attributeGroup> </xs:redefine>