facebook google plus twitter
Webucator's Free XML Schema Tutorial

Lesson: Simple-Type Elements

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

Tutorial

Lesson Goals

  • To use XML Schema's built-in simple types.
  • To derive your own types.
  • To define list types.
  • To define union types.
  • To declare global simple-type elements.
  • To set default and fixed values.
  • To allow for nil values.

Overview

Simple-type elements have no children or attributes. For example, the Name element below is a simple-type element; whereas the Person and HomePage elements are not.

Code Sample:

SimpleTypes/Demos/SimpleType.xml
<?xml version="1.0"?>
<Person>
	<Name>Mark Twain</Name>
	<HomePage URL="http://www.marktwain.com"/>
</Person>

As the diagram below shows, a simple type can either be built-in or user-derived. In this lesson, we will examine both.

Built-in Simple Types

XML Schema specifies 44 built-in types, 19 of which are primitive.

19 Primitive Data Types

The 19 built-in primitive types are listed below.

  1. string
  2. boolean
  3. decimal
  4. float
  5. double
  6. duration
  7. dateTime
  8. time
  9. date
  10. gYearMonth
  11. gYear
  12. gMonthDay
  13. gDay
  14. gMonth
  15. hexBinary
  16. base64Binary
  17. anyURI
  18. QName
  19. NOTATION

Built-in Derived Data Types

The other 25 built-in data types are derived from one of the primitive types listed above.

  1. normalizedString
  2. token
  3. language
  4. NMTOKEN
  5. NMTOKENS
  6. Name
  7. NCName
  8. ID
  9. IDREF
  10. IDREFS
  11. ENTITY
  12. ENTITIES
  13. integer
  14. nonPositiveInteger
  15. negativeInteger
  16. long
  17. int
  18. short
  19. byte
  20. nonNegativeInteger
  21. unsignedLong
  22. unsignedInt
  23. unsignedShort
  24. unsignedByte
  25. positiveInteger

Defining a Simple-type Element

A simple-type element is defined using the type attribute.

Code Sample:

SimpleTypes/Demos/Author.xsd
<?xml version="1.0" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:element name="Author">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="FirstName" type="xs:string"/>
				<xs:element name="LastName" type="xs:string"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Notice the FirstName and LastName elements in the code sample above. They are not explicitly defined as simple type elements. Instead, the type is defined with the type attribute. Because the value (string in both cases) is a simple type, the elements themselves are simple-type elements.

Building a Simple Schema

Duration: 10 to 15 minutes.

In this exercise, you will build a simple XML schema.

  1. Open SimpleTypes/Exercises/Song.xsd for editing.
  2. Between the open and close xs:sequence tags, declare three new elements:
    • Title of type xs:string.
    • Year of type xs:gYear.
    • Artist of type xs:string.
  3. Save the file.
  4. Try to validate LoveMeDo.xml against the schema you just created. If the XML document is invalid, fix your schema.

Code Sample:

SimpleTypes/Exercises/Song.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:element name="Song">
		<xs:complexType>
			<xs:sequence>
				<!--
					Add three simple-type elements:
					1. Title
					2. Year
					3. Artist
				-->
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Solution:

SimpleTypes/Solutions/Song.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:element name="Song">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Title" type="xs:string"/>
				<xs:element name="Year" type="xs:gYear"/>
				<xs:element name="Artist" type="xs:string"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

User-derived Simple Types

A schema author can derive a new simple type using the <xs:simpleType> element. This simple type can then be used in the same way that built-in simple types are.

Simple types are derived by restricting built-in simple types or other user-derived simple types. For example, you might want to create a simple type called password that is an eight-character string. To do so, you would start with the xs:string type and restrict its length to eight characters. This is done nesting the <xs:restriction> element inside of the <xs:simpleType> element.

Code Sample:

SimpleTypes/Demos/Password.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="Password">
		<xs:restriction base="xs:string">
			<xs:length value="8"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="User">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="PW" type="Password"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/Password.xml
<?xml version="1.0"?>
<User xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="Password.xsd">
	<PW>MyPasWrd</PW>
</User>

Applying Facets

Simple types can be derived by applying one or more of the following facets.

  • length
  • minLength
  • maxLength
  • pattern
  • enumeration
  • whiteSpace
  • minInclusive
  • minExclusive
  • maxInclusive
  • maxExclusive
  • totalDigits
  • fractionDigits

Controlling Length

The length of a string can be controlled with the length, minLength, and maxLength facets. We used the length facet in the example above to create a Password simple type as an eight-character string. We could use minLength and maxLength to allow passwords that were between six and twelve characters in length.

The schema below shows how this is done. The two XML instances shown below it are both valid, because the length of the password is between six and twelve characters.

Code Sample:

SimpleTypes/Demos/Password2.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="Password">
		<xs:restriction base="xs:string">
			<xs:minLength value="6"/>
			<xs:maxLength value="12"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="User">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="PW" type="Password"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/Password2.xml
<?xml version="1.0"?>
<User xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="Password2.xsd">
	<PW>MyPass</PW>
</User>

Code Sample:

SimpleTypes/Demos/Password2b.xml
<?xml version="1.0"?>
<User xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="Password2.xsd">
	<PW>MyPassWord</PW>
</User>

Specifying Patterns

Patterns are specified using the xs:pattern element and regular expressions. For example, you could use the xs:pattern element to restrict the Password simple type to consist of between six and twelve characters, which can only be lowercase and uppercase letters and underscores.

Code Sample:

SimpleTypes/Demos/Password3.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="Password">
		<xs:restriction base="xs:string">
			<xs:pattern value="[A-Za-z_]{6,12}"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="User">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="PW" type="Password"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/Password3.xml
<?xml version="1.0"?>
<User xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="Password3.xsd">
	<PW>MyPassword</PW>
</User>

Working with Numbers

Numeric simple types can be derived by limiting the value to a certain range using minExclusive, minInclusive, maxExclusive, and maxInclusive. You can also limit the total number of digits and the number of digits after the decimal point using totalDigits and fractionDigits, respectively.

Mins and Maxs

The following example shows how to derive a simple type called Salary, which is a decimal between 10,000 and 90,000.

Code Sample:

SimpleTypes/Demos/Employee.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="Salary">
		<xs:restriction base="xs:decimal">
			<xs:minInclusive value="10000"/>
			<xs:maxInclusive value="90000"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="Employee">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Salary" type="Salary"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/JohnSmith.xml
<?xml version="1.0"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="Employee.xsd">
	<Salary>55000</Salary>
</Employee>

Number of Digits

Using totalDigits and fractionDigits, we can further specify that the Salary type should consist of seven digits, two of which come after the decimal point. Both totalDigits and fractionDigits are maximums. That is, if totalDigits is specified as 5 and fractionDigits is specified as 2, a valid number could have no more than five digits total and no more than two digits after the decimal point.

Code Sample:

SimpleTypes/Demos/Employee2.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="Salary">
		<xs:restriction base="xs:decimal">
			<xs:minInclusive value="10000"/>
			<xs:maxInclusive value="90000"/>
			<xs:fractionDigits value="2"/>
			<xs:totalDigits value="7"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="Employee">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Salary" type="Salary"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/MarySmith.xml
<?xml version="1.0"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="Employee2.xsd">
	<Salary>55000.00</Salary>
</Employee>

Enumerations

A derived type can be a list of possible values. For example, the JobTitle element could be a list of pre-defined job titles.

Code Sample:

SimpleTypes/Demos/Employee3.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="Salary">
		<xs:restriction base="xs:decimal">
			<xs:minInclusive value="10000"/>
			<xs:maxInclusive value="90000"/>
			<xs:fractionDigits value="2"/>
			<xs:totalDigits value="7"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="JobTitle">
		<xs:restriction base="xs:string">
			<xs:enumeration value="Sales Manager"/>
			<xs:enumeration value="Salesperson"/>
			<xs:enumeration value="Receptionist"/>
			<xs:enumeration value="Developer"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="Employee">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Salary" type="Salary"/>
				<xs:element name="Title" type="JobTitle"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/SteveSmith.xml
<?xml version="1.0"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="Employee3.xsd">
	<Salary>90000.00</Salary>
	<Title>Sales Manager</Title>
</Employee>

Whitespace-handling

By default, whitespace in elements of the datatype xs:string is preserved in XML documents; however, this can be changed for datatypes derived from xs:string. This is done with the xs:whiteSpace element, the value of which must be one of the following.

  • preserve - whitespace is not normalized. That is to say, it is kept as is.
  • replace - all tabs, line feeds, and carriage returns are replaced by single spaces.
  • collapse - all tabs, line feeds, and carriage returns are replaced by single spaces and then all groups of single spaces are replaced with one single space. All leading and trailing spaces are then removed (i.e, trimmed).

In SimpleTypes/Demos/Password.xsd, we looked at restricting the length of a Password datatype to eight characters using the xs:length element. If whitespace is preserved, then leading and trailing spaces are considered part of the password. In the following example, we set xs:whiteSpace to collapse, thereby discounting any leading or trailing whitespace. As you can see, this allows the XML instance author to format the document without consideration of whitespace.

Code Sample:

SimpleTypes/Demos/Password4.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="Password">
		<xs:restriction base="xs:string">
			<xs:length value="8"/>
			<xs:whiteSpace value="collapse"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="User">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="PW" type="Password"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/Password4.xml
<?xml version="1.0"?>
<User xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="Password4.xsd">
	<PW>
		12345678
	</PW>
</User>

Restricting Element Content

Duration: 15 to 20 minutes.

In this exercise, you will further restrict the Song schema, so that the Title and Artist elements will have a specified pattern and the Year will be 1950 or later.

  1. Open SimpleTypes/Exercises/Song.xsd and save it as Song2.xsd in the same directory.
  2. Define a simple type called ProperName that follows this pattern. Note that the only space in the pattern is the one before the question mark.
    ([A-Z0-9][A-Za-z0-9\-']* ?)+
  3. Change the Title and Artist elements to be of the ProperName type.
  4. Define another simple type called Year, which is derived from gYear and only accepts years between 1950 and 1970, inclusive.
  5. Change the Year element to be of the Year type.
  6. Try to validate SimpleTypes/Exercises/CantBuyMeLove.xml against the schema you just created. If the XML document is invalid, fix your schema.

Code Sample:

SimpleTypes/Exercises/Song.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:element name="Song">
		<xs:complexType>
			<xs:sequence>
				<!--
					Add three simple-type elements:
					1. Title
					2. Year
					3. Artist
				-->
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Solution:

SimpleTypes/Solutions/Song2.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="ProperName">
		<xs:restriction base="xs:string">
			<xs:pattern value="([A-Z0-9][A-Za-z0-9\-']* ?)+"/>
			<xs:whiteSpace value="collapse"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="Year">
		<xs:restriction base="xs:gYear">
			<xs:minInclusive value="1950"/>
			<xs:maxInclusive value="1970"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="Song">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Title" type="ProperName"/>
				<xs:element name="Year" type="Year"/>
				<xs:element name="Artist" type="ProperName"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Specifying Element Type Locally

So far in this lesson, we have been defining simple types globally and then setting the type attribute of element declarations to be of our derived simple types. This makes it easy to reuse a simple type across multiple elements, as we saw with the ProperName type in the last exercise.

It is also possible to define the type of an element locally. The type is then unnamed and applicable only to that element. The only reason to do this is to clearly show that the type is specific to that element and not meant for reuse.

Code Sample:

SimpleTypes/Demos/PasswordLocal.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:element name="User">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="PW">
					<xs:simpleType>
						<xs:restriction base="xs:string">
							<xs:length value="8"/>
							<xs:whiteSpace value="collapse"/>
						</xs:restriction>
					</xs:simpleType>
				</xs:element>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Nonatomic Types

All of XML Schema's built-in types are atomic, meaning that they cannot be broken down into meaningful bits. XML Schema provides for two nonatomic types: lists and unions.

Lists

List types are sequences of atomic types separated by whitespace; you can have a list of integers or a list of dates. Lists should not be confused with enumerations. Enumerations provide optional values for an element. Lists represent one or more values within an element.

Code Sample:

SimpleTypes/Demos/EmployeeList.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="Salary">
		<xs:restriction base="xs:decimal">
			<xs:minInclusive value="10000"/>
			<xs:maxInclusive value="90000"/>
			<xs:fractionDigits value="2"/>
			<xs:totalDigits value="7"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="JobTitle">
		<xs:restriction base="xs:string">
			<xs:enumeration value="Sales Manager"/>
			<xs:enumeration value="Salesperson"/>
			<xs:enumeration value="Receptionist"/>
			<xs:enumeration value="Developer"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="DateList">
		<xs:list itemType="xs:date"/>
	</xs:simpleType>
	<xs:element name="Employee">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Salary" type="Salary"/>
				<xs:element name="Title" type="JobTitle"/>
				<xs:element name="VacationDays" type="DateList"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/SandySmith.xml
<?xml version="1.0"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="EmployeeList.xsd">
	<Salary>44000</Salary>
	<Title>Salesperson</Title>
	<VacationDays>2006-08-13 2006-08-14 2006-08-15</VacationDays>
</Employee>

Unions

Union types are groupings of types, essentially allowing for the value of an element to be of more than one type. In the example below, two atomic simple types are derived: RunningRace and Gymnastics. A third simple type, Event, is then derived as a union of the previous two. The Event element is of the Event type, which means that it can either be of the RunningRace or the Gymnastics type.

Code Sample:

SimpleTypes/Demos/Program.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="RunningRace">
		<xs:restriction base="xs:string">
			<xs:enumeration value="100 meters"/>
			<xs:enumeration value="10 kilometers"/>
			<xs:enumeration value="440 yards"/>
			<xs:enumeration value="10 miles"/>
			<xs:enumeration value="Marathon"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="Gymnastics">
		<xs:restriction base="xs:string">
			<xs:enumeration value="Vault"/>
			<xs:enumeration value="Floor"/>
			<xs:enumeration value="Rings"/>
			<xs:enumeration value="Beam"/>
			<xs:enumeration value="Uneven Bars"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="Event">
		<xs:union memberTypes="RunningRace Gymnastics"/>
	</xs:simpleType>
	<xs:element name="Program">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Event" type="Event"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/100Meters.xml
<?xml version="1.0"?>
<Program xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="Program.xsd">
	<Event>100 meters</Event>
</Program>

Adding Nonatomic Types

Duration: 10 to 15 minutes.

In this exercise, you will add a nonatomic type to the song schema.

  1. Open SimpleTypes/Exercises/Song2.xsd and save it as Song3.xsd in the same directory.
  2. Define a new simple type called SongLength, which is an enumeration of three values: "Short", "Medium', and "Long".
  3. Define another new simple type called SongTime, which is a union of xs:duration and SongLength.
  4. At the end of the sequence of elements within the Song element, insert an additional element, Length, which is of the SongTime datatype.
  5. Try to validate SimpleTypes/Exercises/TicketToRide.xml and SimpleTypes/Exercises/EleanorRigby.xml against the schema you just created. If either XML document is invalid, fix your schema.

Solution:

SimpleTypes/Solutions/Song3.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="ProperName">
		<xs:restriction base="xs:string">
			<xs:whiteSpace value="collapse"/>
			<xs:pattern value="([A-Z0-9][A-Za-z0-9\-']* ?)+"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="Year">
		<xs:restriction base="xs:gYear">
			<xs:minInclusive value="1950"/>
			<xs:maxInclusive value="1970"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="SongLength">
		<xs:restriction base="xs:string">
			<xs:enumeration value="Short"/>
			<xs:enumeration value="Medium"/>
			<xs:enumeration value="Long"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="SongTime">
		<xs:union memberTypes="xs:duration SongLength"/>
	</xs:simpleType>
	<xs:element name="Song">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Title" type="ProperName"/>
				<xs:element name="Year" type="Year"/>
				<xs:element name="Artist" type="ProperName"/>
				<xs:element name="Length" type="SongTime"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Declaring Global Simple-Type Elements

When an element declaration is a child of the xs:schema element, the declared element is global. Global elements can be referenced by other element declarations, allowing for element reuse. Take a look at the following example.

Code Sample:

SimpleTypes/Demos/AuthorGlobal.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:element name="FirstName" type="xs:string"/>
	<xs:element name="LastName" type="xs:string"/>
	<xs:element name="Author">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="FirstName"/>
				<xs:element ref="LastName"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

In this example, the FirstName and LastName elements are both declared globally. The global elements are then referenced as children of the Author sequence.

Global vs. Local Simple-Type Elements

The major advantage of declaring an element globally is that the element can then be referenced throughout the schema. This makes the code more modular and easier to maintain. For example, suppose that the song schema contained MusicWriter, LyricsWriter, and Singer elements. Each of these elements might have the child element Name. If the Name element is declared globally, any changes to that element can be made in one location.

The major disadvantage of declaring elements globally is that all global elements must have unique names.

Code Sample:

SimpleTypes/Demos/BookLocal.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="PersonTitle">
		<xs:restriction base="xs:string">
			<xs:enumeration value="Mr."/>
			<xs:enumeration value="Ms."/>
			<xs:enumeration value="Dr."/>
		</xs:restriction>
	</xs:simpleType>
	<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="Title" type="PersonTitle"/>
							<xs:element name="Name" type="xs:string"/>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Notice that there are two elements named Title, which can appear in different locations in the XML instance and are of different types. When the Title element appears at the root of the XML instance, its value can be any string; whereas, when it appears as a child of Author, its value is limited to "Mr.", "Ms.", or "Dr."

The example below defines a similar content model; however, because the elements are declared globally, the name Title cannot be used twice.

Code Sample:

SimpleTypes/Demos/BookGlobal.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="PersonTitle">
		<xs:restriction base="xs:string">
			<xs:enumeration value="Mr."/>
			<xs:enumeration value="Ms."/>
			<xs:enumeration value="Dr."/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="BookTitle" type="xs:string"/>
	<xs:element name="Title" type="PersonTitle"/>
	<xs:element name="Name" type="xs:string"/>
	<xs:element name="Book">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="BookTitle"/>
				<xs:element name="Author">
					<xs:complexType>
						<xs:sequence>
							<xs:element ref="Title"/>
							<xs:element ref="Name"/>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Converting Simple-Type Element Declarations from Local to Global

Duration: 10 to 20 minutes.

In this exercise, you will convert the element declarations in the song schema from local to global.

  1. Open SimpleTypes/Exercises/Song3.xsd and save it as Song4.xsd in the same directory.
  2. Change the Title, Year, Artist, and Length elements to be declared globally.
  3. Try to validate SimpleTypes/Exercises/StrawberryFields.xml against the schema you just created. If the XML document is invalid, fix your schema.

Solution:

SimpleTypes/Solutions/Song4.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="ProperName">
		<xs:restriction base="xs:string">
			<xs:whiteSpace value="collapse"/>
			<xs:pattern value="([A-Z0-9][A-Za-z0-9\-']* ?)+"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="Year">
		<xs:restriction base="xs:gYear">
			<xs:minInclusive value="1950"/>
			<xs:maxInclusive value="1970"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="SongLength">
		<xs:restriction base="xs:string">
			<xs:enumeration value="Short"/>
			<xs:enumeration value="Medium"/>
			<xs:enumeration value="Long"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="SongTime">
		<xs:union memberTypes="xs:duration SongLength"/>
	</xs:simpleType>
	<xs:element name="Title" type="ProperName"/>
	<xs:element name="Year" type="Year"/>
	<xs:element name="Artist" type="ProperName"/>
	<xs:element name="Length" type="SongTime"/>
	<xs:element name="Song">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="Title"/>
				<xs:element ref="Year"/>
				<xs:element ref="Artist"/>
				<xs:element ref="Length"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Default Values

Elements that do not have any children can have default values. To specify a default value, use the default attribute of the xs:element element.

Code Sample:

SimpleTypes/Demos/EmployeeDefault.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
---- C O D E   O M I T T E D ----

	<xs:element name="Employee">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Salary" type="Salary"/>
				<xs:element name="Title" type="JobTitle" default="Salesperson"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

When defaults are set in the XML schema, the following rules apply for the instance document.

  1. If the element appears in the document with content, the default value is ignored.
  2. If the element appears without content, the default value is applied.
  3. If the element does not appear, the element is left out. In other words, providing a default value does not imply that the element should be inserted if the XML instance author leaves it out.

Examine the following XML instance. The Title element cannot be empty; it requires one of the values from the enumeration defined in the JobTitle simple type. However, in accordance with number 2 above, the schema processor applies the default value of Salesperson to the Title element, so the instance validates successfully.

Code Sample:

SimpleTypes/Demos/MikeSmith.xml
<?xml version="1.0"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="EmployeeDefault.xsd">
	<Salary>90000</Salary>
	<Title/>
</Employee>

Fixed Values

Element values can be fixed, meaning that, if they appear in the instance document, they must contain a specified value. Fixed elements are often used for boolean switches.

Code Sample:

SimpleTypes/Demos/EmployeeFixed.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:simpleType name="Salary">
		<xs:restriction base="xs:decimal">
			<xs:minInclusive value="10000"/>
			<xs:maxInclusive value="90000"/>
			<xs:fractionDigits value="2"/>
			<xs:totalDigits value="7"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="JobTitle">
		<xs:restriction base="xs:string">
			<xs:enumeration value="Sales Manager"/>
			<xs:enumeration value="Salesperson"/>
			<xs:enumeration value="Receptionist"/>
			<xs:enumeration value="Developer"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:element name="Employee">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Salary" type="Salary"/>
				<xs:element name="Title" type="JobTitle"/>
				<xs:element name="Status" type="xs:string" fixed="current" 
					minOccurs="0"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

The MinOccurs attribute is used to make the Status element optional. However, if it is used, it must contain the value current or be left empty, in which case, the value current is implied. The file SimpleTypes/Demos/LauraSmith.xml in the Demos folder validates against this schema.

Nil Values

When an optional element is left out of an XML instance, it has no clear meaning. For example, suppose a schema declares a Name element as having required FirstName and LastName elements and an optional MiddleName element. And suppose a particular instance of this schema does not include the MiddleName element. Does this mean that the instance author did not know the middle name of the person in question or does it mean the person in question has no middle name?

Setting the nillable attribute of xs:element to true indicates that such elements can be set to nil by setting the xsi:nil attribute to true.

Code Sample:

SimpleTypes/Demos/AuthorNillable.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:element name="Author">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="FirstName" type="xs:string"/>
				<xs:element name="MiddleName" type="xs:string" nillable="true"/>
				<xs:element name="LastName" type="xs:string"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Code Sample:

SimpleTypes/Demos/MarkTwain.xml
<?xml version="1.0"?>
<Author xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:noNamespaceSchemaLocation="AuthorNillable.xsd">
	<FirstName>Mark</FirstName>
	<MiddleName xsi:nil="true"/>
	<LastName>Twain</LastName>
</Author>

By including the MiddleName element and setting xsi:nil to true, we are explicitly stating that we do not know anything about Mark Twain's middle name. He might have had one, but we don't know what it is, and if we do, we're not saying.

This is, of course, somewhat strange. It implies that if we had simply left the MiddleName out, we would be indicating that Mark Twain has no middle name. The important thing is that the application consuming your XML data can differentiate between nil values, empty elements, and missing elements.