facebook google plus twitter
Webucator's Free XML Schema Tutorial

Lesson: Reusing Schema Components

Welcome to our free XML Schema tutorial. This tutorial is based on Webucator's Introduction to XML Schema course.

Lesson Goals

  • To define element groups.
  • To define attribute groups.
  • To reuse element and attribute groups.

Overview

We have already seen several methods of reusing schema parts.

  • Declaring elements globally.
  • Declaring attributes globally.
  • Defining global simple types.
  • Defining global complex types.

We will now look at some other methods of reuse.

Groups

Element and attribute groups can be used to create a set structure for reuse. To illustrate the benefit of groups, let's first look at a simple XML instance and its (rather long) schema that does not use groups.

Code Sample:

ReusingComponents/Demos/WinnieThePooh.xml
<?xml version="1.0"?>
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="Book.xsd">
	<Title>Winnie the Pooh</Title>
	<Author Title="Mr." BirthYear="1882">
		<FirstName>A.</FirstName>
		<MiddleName>A.</MiddleName>
		<LastName>Milne</LastName>
		<Specialty>Childrens</Specialty>
	</Author>
	<Illustrator Title="Mr." BirthYear="1879">
		<FirstName>Ernest</FirstName>
		<MiddleName>H.</MiddleName>
		<LastName>Shepard</LastName>
	</Illustrator>
</Book>

Code Sample:

ReusingComponents/Demos/Book.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:element name="Book">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Title" type="xs:string"/>
				<xs:element name="Author">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="FirstName" type="xs:string"/>
							<xs:element name="MiddleName" type="xs:string" minOccurs="0"/>
							<xs:element name="LastName" type="xs:string"/>
							<xs:element name="Specialty">
								<xs:simpleType>
										<xs:restriction base="xs:string">
											<xs:enumeration value="Mystery"/>
											<xs:enumeration value="Humor"/>
											<xs:enumeration value="Horror"/>
											<xs:enumeration value="Childrens"/>
										</xs:restriction>
								</xs:simpleType>
							</xs:element>
						</xs:sequence>
						<xs:attribute name="Title">
							<xs:simpleType>
								<xs:restriction base="xs:string">
									<xs:enumeration value="Mr."/>
									<xs:enumeration value="Ms."/>
									<xs:enumeration value="Dr."/>
								</xs:restriction>
							</xs:simpleType>
						</xs:attribute>
						<xs:attribute name="BirthYear" type="xs:gYear"/>
					</xs:complexType>
				</xs:element>
				<xs:element name="Illustrator" minOccurs="0">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="FirstName" type="xs:string"/>
							<xs:element name="MiddleName" type="xs:string" minOccurs="0"/>
							<xs:element name="LastName" type="xs:string"/>
						</xs:sequence>
						<xs:attribute name="Title">
							<xs:simpleType>
								<xs:restriction base="xs:string">
									<xs:enumeration value="Mr."/>
									<xs:enumeration value="Ms."/>
									<xs:enumeration value="Dr."/>
								</xs:restriction>
							</xs:simpleType>
						</xs:attribute>
						<xs:attribute name="BirthYear" type="xs:gYear"/>
					</xs:complexType>
				</xs:element>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

The Author element and the Illustrator element have some elements and attributes in common. Let's see how we can make this code more modular.

Element Groups

First, we'll look at how we can group the FirstName, MiddleName, and LastName elements with xs:group to avoid rewriting the elements.

Code Sample:

ReusingComponents/Demos/Book2.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:group name="GroupName">
		<xs:sequence>
			<xs:element name="FirstName" type="xs:string"/>
			<xs:element name="MiddleName" type="xs:string" minOccurs="0"/>
			<xs:element name="LastName" type="xs:string"/>
		</xs:sequence>
	</xs:group>
	<xs:element name="Book">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Title" type="xs:string"/>
				<xs:element name="Author">
					<xs:complexType>
						<xs:sequence>
							<xs:group ref="GroupName"/>
---- C O D E   O M I T T E D ----

					</xs:complexType>
				</xs:element>
				<xs:element name="Illustrator" minOccurs="0">
					<xs:complexType>
						<xs:sequence>
							<xs:group ref="GroupName"/>
						</xs:sequence>
---- C O D E   O M I T T E D ----

					</xs:complexType>
				</xs:element>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Attribute Groups

Now let's look at how we can use the xs:attributeGroup element to avoiding rewriting those attributes.

Code Sample:

ReusingComponents/Demos/Book3.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:group name="GroupName">
		<xs:sequence>
			<xs:element name="FirstName" type="xs:string"/>
			<xs:element name="MiddleName" type="xs:string" minOccurs="0"/>
			<xs:element name="LastName" type="xs:string"/>
		</xs:sequence>
	</xs:group>
	<xs:attributeGroup name="AttGroupPerson">
		<xs:attribute name="Title">
			<xs:simpleType>
				<xs:restriction base="xs:string">
					<xs:enumeration value="Mr."/>
					<xs:enumeration value="Ms."/>
					<xs:enumeration value="Dr."/>
				</xs:restriction>
			</xs:simpleType>
		</xs:attribute>
		<xs:attribute name="BirthYear" type="xs:gYear"/>
	</xs:attributeGroup>
	<xs:element name="Book">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Title" type="xs:string"/>
				<xs:element name="Author">
					<xs:complexType>
						<xs:sequence>
							<xs:group ref="GroupName"/>
							<xs:element name="Specialty">
								<xs:simpleType>
									<xs:restriction base="xs:string">
										<xs:enumeration value="Mystery"/>
										<xs:enumeration value="Humor"/>
										<xs:enumeration value="Horror"/>
										<xs:enumeration value="Childrens"/>
									</xs:restriction>
								</xs:simpleType>
							</xs:element>
						</xs:sequence>
						<xs:attributeGroup ref="AttGroupPerson"/>
					</xs:complexType>
				</xs:element>
				<xs:element name="Illustrator" minOccurs="0">
					<xs:complexType>
						<xs:sequence>
							<xs:group ref="GroupName"/>
						</xs:sequence>
						<xs:attributeGroup ref="AttGroupPerson"/>
					</xs:complexType>
				</xs:element>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Extending Complex Types

New complex types can be derived by extending existing complex types. Both elements and attributes can be added in the new type, but nothing in the existing type can be overridden. New elements are appended to the content model, such that the original elements and new elements act as two groups that must appear in sequence.

The example below shows how the Person element can be extended.

Code Sample:

ReusingComponents/Demos/Book4.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:complexType name="Person">
		<xs:sequence>
			<xs:element name="FirstName" type="xs:string"/>
			<xs:element name="MiddleName" type="xs:string" minOccurs="0"/>
			<xs:element name="LastName" type="xs:string"/>
		</xs:sequence>
		<xs:attributeGroup ref="AttGroupPerson"/>
	</xs:complexType>
	<xs:complexType name="PersonExtended">
		<xs:complexContent>
			<xs:extension base="Person">
				<xs:sequence>
					<xs:element name="Specialty">
						<xs:simpleType>
							<xs:restriction base="xs:string">
								<xs:enumeration value="Mystery"/>
								<xs:enumeration value="Humor"/>
								<xs:enumeration value="Horror"/>
								<xs:enumeration value="Childrens"/>
							</xs:restriction>
						</xs:simpleType>
					</xs:element>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
---- C O D E   O M I T T E D ----

	<xs:element name="Book">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Title" type="xs:string"/>
				<xs:element name="Author" type="PersonExtended"/>
				<xs:element name="Illustrator" type="Person" minOccurs="0"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

No material changes have been made from Book.xsd to Book4.xsd. The WinnieThePooh.xml file would be valid according to all of these schemas; however the last one would be easier to maintain and build upon than the first.

Abstract Types

When a type is made abstract, it cannot be used directly in an XML instance. One of its derived types must be used instead. The derived type is identified in the instance document using the xsi:type attribute. The schema below includes an abstract type with two derivations.

Code Sample:

ReusingComponents/Demos/Animals.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:complexType name="Measurement">
		<xs:simpleContent>
			<xs:extension base="xs:integer">
				<xs:attribute name="units" type="xs:string"/>
			</xs:extension>
		</xs:simpleContent>
	</xs:complexType>
	<xs:element name="Weight" type="Measurement"/>
	<xs:element name="Name" type="xs:string"/>
	<!--Abstract Type-->
	<xs:complexType name="Animal" abstract="true">
		<xs:sequence>
			<xs:element ref="Name"/>
			<xs:element ref="Weight"/>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="Dog">
		<xs:complexContent>
			<xs:extension base="Animal"/>
		</xs:complexContent>
	</xs:complexType>
	<xs:complexType name="Bird">
		<xs:complexContent>
			<xs:extension base="Animal">
				<xs:sequence>
					<xs:element name="WingSpan" type="Measurement"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
	<xs:element name="Animals">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Animal" type="Animal" maxOccurs="unbounded"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

The Animal type is declared as abstract by setting the abstract attribute to true. It is extended by the Dog and Bird types. The Dog type doesn't actually modify the original type at all, but the Bird type addes a WingSpan element.

Note that the Animal element declared within the Animals element is of the abstract type Animal.

Let's now look at an instance document of this schema:

Code Sample:

ReusingComponents/Demos/Animals.xml
<?xml version="1.0" encoding="UTF-8"?>
<Animals xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Animals.xsd">
	<Animal xsi:type="Dog">
		<Name>Rover</Name>
		<Weight units="pounds">80</Weight>
	</Animal>
	<Animal xsi:type="Bird">
		<Name>Tweetie</Name>
		<Weight units="grams">15</Weight>
		<WingSpan units="cm">20</WingSpan>
	</Animal>
</Animals>

Notice that each of the Animal elements includes an xsi:type attribute. If we were to remove that attribute, the instance would be become invalid because the Animal element is of an abstract type.