Complex-Type Elements
- To declare complex-type elements.
- To use content models.
- To control cardinality (quantity of elements).
- To declare elements of mixed types.
- To define named complex types.
Overview
Complex-type elements have attributes, child elements, or some combination of the two. For example, the Name and HomePage elements below are both complex-type elements.
Code Sample: ComplexTypes/Demos/ComplexType.xml
<?xml version="1.0"?> <Person> <Name> <FirstName>Mark</FirstName> <LastName>Twain</LastName> </Name> <HomePage URL="http://www.marktwain.com"/> </Person>
As the diagram below shows, a complex-type element can be empty, contain simple content such as a string, or can contain complex content such as a sequence of elements.
Whereas it is not necessary to explicitly declare that a simple-type element is a simple type, it is necessary to specify that a complex-type element is a complex type. This is done with the xs:complexType element as shown below.
<xs:element name="ElementName"> <xs:complexType> <!--Content Model Goes Here--> </xs:complexType> </xs:element>
Content Models
Content models are used to indicate the structure and order in which child elements can appear within their parent element. Content models are made up of model groups. The three types of model groups are listed below.
- xs:sequence - the elements must appear in the order specified.
- xs:all - the elements must appear, but order is not important.
- xs:choice - only one of the elements can appear.
xs:sequence
The following sample shows the syntax for declaring a complex-type element as a sequence, meaning that the elements must show up in the order they are declared.
<xs:element name="ElementName"> <xs:complexType> <xs:sequence> <xs:element name="Child1" type="xs:string"/> <xs:element name="Child2" type="xs:string"/> <xs:element name="Child3" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>
xs:all
The following sample shows the syntax for declaring a complex-type element as a conjunction, meaning that the elements can show up in any order.
<xs:element name="ElementName"> <xs:complexType> <xs:all> <xs:element name="Child1" type="xs:string"/> <xs:element name="Child2" type="xs:string"/> <xs:element name="Child3" type="xs:string"/> </xs:all> </xs:complexType> </xs:element>
xs:choice
The following sample shows the syntax for declaring a complex-type element as a choice, meaning that only one of the child elements may show up.
<xs:element name="ElementName"> <xs:complexType> <xs:choice> <xs:element name="Child1" type="xs:string"/> <xs:element name="Child2" type="xs:string"/> <xs:element name="Child3" type="xs:string"/> </xs:choice> </xs:complexType> </xs:element>
Complex Model Groups
In the examples above, the model groups are all made up of simple-type elements. However, complex-type elements can contain other complex-type elements.
<xs:element name="ElementName">
<xs:complexType>
<xs:choice>
<xs:element name="Child1" type="xs:string"/>
<xs:element name="Child2">
<xs:complexType>
<xs:sequence>
<xs:element name="GC1" type="xs:string"/>
<xs:element name="GC2" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Child3" type="xs:string"/>
</xs:choice>
</xs:complexType>
</xs:element>Furthermore, model groups can be nested within each other. The following example illustrates this. Notice that the choice model group, which allows for either a Salary element or a Wage element is nested with in a sequence model group. Both of the subsequent instances are valid according to this schema.
Code Sample: ComplexTypes/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="Name">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName"/>
<xs:element name="LastName"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:choice>
<xs:element name="Salary" type="Salary"/>
<xs:element name="Wage" type="xs:decimal"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Code Sample: ComplexTypes/Demos/DaveSmith.xml
<?xml version="1.0"?> <Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Employee.xsd"> <Name> <FirstName>Dave</FirstName> <LastName>Smith</LastName> </Name> <Salary>90000</Salary> </Employee>
Code Sample: ComplexTypes/Demos/JillSmith.xml
<?xml version="1.0"?> <Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Employee.xsd"> <Name> <FirstName>Jill</FirstName> <LastName>Smith</LastName> </Name> <Wage>20.50</Wage> </Employee>
Occurrence Constraints
By default, elements that are declared locally must show up once and only once within their parent. This constraint can be changed using the minOccurs and maxOccurs attributes. The default value of each of these attributes is 1. The value of minOccurs can be any non-negative integer. The value of maxOccurs can be any positive integer or unbounded, meaning that the element can appear an infinite number of times.
The example below shows how minOccurs can be used to make an element optional and how maxOccurs can be used to allow an element to be repeated indefinitely.
Code Sample: ComplexTypes/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:restriction>
</xs:simpleType>
<xs:element name="Employee">
<xs:complexType>
<xs:sequence>
<xs:element name="Name">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName"/>
<xs:element name="MiddleName" minOccurs="0"/>
<xs:element name="LastName"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:choice>
<xs:element name="Salary" type="Salary"/>
<xs:element name="Wage" type="xs:decimal"/>
</xs:choice>
<xs:element name="Responsibilities">
<xs:complexType>
<xs:sequence>
<xs:element name="Responsibility" type="xs:string"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Note that minOccurs and maxOccurs can also be applied to model groups (e.g, xs:sequence) to control the number of times a model group can be repeated.
Declaring Global Complex-Type Elements
As with simple-type elements, complex-type elements can be declared globally by placing the element declaration as a child of the xs:schema element.
Globally declared elements cannot take occurrence constraints. However, the minOccurs and maxOccurs constraints can be applied to references to globally declared elements. To illustrate, look at the following example. Notice that all elements, both simple-type and complex-type, are declared globally and then referenced within the model groups. Some of the references (e.g, Responsibilities) have occurrence constraints assigned to them.
Code Sample: ComplexTypes/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:restriction>
</xs:simpleType>
<xs:element name="Name">
<xs:complexType>
<xs:sequence>
<xs:element ref="FirstName"/>
<xs:element ref="MiddleName" minOccurs="0"/>
<xs:element ref="LastName"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FirstName"/>
<xs:element name="MiddleName"/>
<xs:element name="LastName"/>
<xs:element name="Wage" type="xs:decimal"/>
<xs:element name="Salary" type="Salary"/>
<xs:element name="Responsibilities">
<xs:complexType>
<xs:sequence>
<xs:element ref="Responsibility" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Responsibility" type="xs:string"/>
<xs:element name="Employee">
<xs:complexType>
<xs:sequence>
<xs:element ref="Name"/>
<xs:choice>
<xs:element ref="Salary"/>
<xs:element ref="Wage"/>
</xs:choice>
<xs:element ref="Responsibilities" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Mixed Content
Sometimes an element will contain both child elements and character text. For example, a para element might contain mostly plain character text, but it could also have other elements (e.g, emphasis) littered throughout the character text.
As an example, let's examine look at the following XML instance document.
Code Sample: ComplexTypes/Demos/PaulMcCartney.xml
<?xml version="1.0"?> <Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Employee4.xsd"> <Name> <FirstName>Paul</FirstName> <LastName>McCartney</LastName> </Name> <Salary>90000</Salary> <Bio> Worked for <Company>the Beatles</Company> as a <JobTitle>Singer</JobTitle>. Worked for <Company>the Beatles</Company> as a <JobTitle>Bass Guitarist</JobTitle>. Worked for <Company>the Wings</Company> as a <JobTitle>Singer</JobTitle>. </Bio> </Employee>
Notice that the Bio element contains child elements Company and JobTitle as well as character text. Such elements are said to contain mixed content. The syntax for declaring elements with mixed content is shown below.
Syntax<xs:element name="ElementName"> <xs:complexType mixed="true"> <xs:sequence> <xs:element name="Child1" type="xs:string"/> <xs:element name="Child2" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>The following example illustrates how to define this in our employee schema.
Code Sample: ComplexTypes/Demos/Employee4.xsd
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">---- Code Omitted ----<xs:element name="Bio"> <xs:complexType mixed="true"> <xs:sequence maxOccurs="unbounded"> <xs:element name="Company" type="xs:string"/> <xs:element name="JobTitle" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>---- Code Omitted ----</xs:schema>
Defining Complex Types Globally
As with simple types, complex types can be defined globally. The example below shows how this is done.
Code Sample: ComplexTypes/Demos/Author.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="LastName" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:element name="Author" type="Person"/> </xs:schema>
As you can see, complex types are defined with the xs:complexType element. The major advantage of defining a complex type globally is that it can be reused. For example, a schema might allow for an Illustrator element as well as an Author element. Both elements could be of type Person. This way, if the Person type is changed later, the change will apply to both elements.
The instance document below will validate properly against the schema above.
Code Sample: ComplexTypes/Demos/MarkTwain.xml
<?xml version="1.0"?> <Author xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Author.xsd"> <FirstName>Mark</FirstName> <LastName>Twain</LastName> </Author>
Complex-Type Elements Conclusion
In this lesson of the XML Schema tutorial, you have learned to work with complex types and complex-type elements. We will now take a look at declaring attributes.
