A schema need not define elements in a namespace (i.e., it's okay to have a schema with no targetNamespace attribute). Instance documents that use elements defined without a namespace may use the noNamespaceSchema attribute to provide the process with the schema's location:
Elements such as first_name and email have simple datatype values (e.g. strings). These types (string, int, etc.), which are prefixed with the xsd qualifier, are called built-in types, because they are defined in the schema of schemas. To declare built-in XML schema simple types in the employeeList XML schema, the schema declaration is straightforward:
minOccurs and maxOccurs constraints determine how many times that particular element may be repeated in the document. The default value of minOccurs and maxOccurs is "1". A special value of unbounded is used to indicate that a particular element may repeat any number of times.
provides mapping between common built-in datatypes and Java types.
Extending Simple Types
The Flute Bank business rules state that all employee_id values must be between 1 and 100,000. An element declaration such as <xsd:element name="employee_id" type="xsd:int"/> enforces the rule only partially: all employee IDs are integer values. To add further constraints on the declaration, XML Schema allows new types to be defined by extending built-in types, using the simpleType element:
<xsd:element name="employee_id">
<xsd:simpleType>
<xsd:restriction base="xsd:int">
<xsd:minInclusive value="1"/>
<xsd:maxInclusive value="100000"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
In the above XML fragment, the employee_id element is declared with a new simple type that is a restriction on the base built-in type int. The restrictions are added to the employee_id element on top of the built-in type restriction of integers and are declared using facets. In this example, the facets added to the int type are minInclusive and maxInclusive. The general syntax for a simpleType is
<xsd:simpleType>
<xsd:restriction base="simple-type">
<xsd:facet value="value"/>
<xsd:facet value="value"/>
...
</xsd:restriction>
</xsd:simpleType>
When a restriction element contains multiple facets, they are ORed if they are enumeration or pattern facets. All other facets are ANDed. The example below shows how a simple type is created by applying a pattern facet to a string datatype. The pattern expression is a regular expression.
<xsd:element >
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{3}-[0-9]{3}-[0-9]{4}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
Table A.1 shows a few facets that can be used with different built-in types to create new simpleTypes.Table A.1: Facets
Built-in type
|
Facet
|
String, all number types
|
enumeration
|
|
<xsd:element name=stateCode
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="CA"/>
<xsd:enumeration value="MA"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element name=employeeType
|
|
Built-in type
|
Facet
|
String, token, normalized String
|
length, minLength, maxLength pattern
|
|
<xsd:element name=stateCode
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:minLength value="2"/>
<xsd:maxLength value="2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element name=employeeType
stateCode length = 2 characters
<xsd:element >
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{5}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
|
|
Complex Types
A complex data structure is modeled with a complexType element. A type created with complexType maps to a Java bean. A complex type can contain other subelements and can have attributes (simpleTypes can have neither). In the following code, employee is a complex type consisting of several elements and one attribute:Table A.2: Facets
Built-in type
|
Facet
|
Most numeric types
|
maxInclusive, minInclusive, maxExclusive, minExclusive
|
|
<xsd:element name="employee_id">
<xsd:simpleType>
<xsd:restriction base="xsd:int">
<xsd:minInclusive value="1"/>
<xsd:maxInclusive value="100000"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
|
|
Built-in type
|
Facet
|
Decimal
|
totalDigits, fractionalDigits
|
|
<xsd:element >
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="10"/>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
|
<xsd:element >
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="employee_id" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="name" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="extn" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="dept" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="email" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attributeGroup ref="employeeAttribute"/>
</xsd:complexType>
</xsd:element>
This example ensures that an employee instance XML will contain elements for employee ID, name, extension, department, and email. You may note that these datatypes of subelements are not defined in the complex type element. Instead, we have chosen to define the subtypes elsewhere in the document and only refer to those definitions here. For example, <xsd:element ref="employee_id" minOccurs="1" maxOccurs="1"/> uses a reference to the employee_id element, which is of a simpleType defined later in the schema. This is not the only way in which a complex type can be defined. It is also possible to define a simpleType inline:
<xsd:element >
<xsd:complexType>
<xsd:sequence>
<xsd:element name="employee_id" minOccurs="1" maxOccurs="1"/>
<xsd:simpleType>
...
</ xsd:simpleType>
<xsd:element>
<xsd:element ref="name" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="extn" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="dept" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="email" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attributeGroup ref="employeeAttribute"/>
</xsd:complexType>
</xsd:element>
However, defining a simpleType with a name and then referring to it wherever it is used lends itself to reuse of types.
sequence and all
sequence signifies that the order of elements declared in it is important. If the order of the subelements within a complexType is not important, the all element can be used to convey this:
<xsd:complexType>
<xsd:all>
<xsd:element ref="employee_id" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="name" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="extn" minOccurs="1" maxOccurs="1"/>
</xsd:all>
</xsd:complexType>
choice
What if we want to express that a Flute employee has either a manager_id or an employee_id? (This is not good design, but the point is to illustrate how the XML schema can handle choices.) choices can appear in a sequence:
<xsd:element >
<xsd:complexType>
<xsd:sequence>
<xsd:choice>
<xsd:element ref="employee_id" />
<xsd:element ref="manager_id" />
</xsd:choice>
<xsd:element ref="name" />
<xsd:element ref="extn" />
<xsd:element ref="email" />
<xsd:element ref="dept"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
In the above fragment, employee must have name, extn, email, and dept and either a manager_id or an employee_id.
attributes
In our Flute Bank example, employees can be described by an employee_type attribute indicating whether they are permanent or contract. In an XML Schema document, an element with one or more attributes can be defined only as a complexType. The example below shows how the attribute declaration is made within the employee complexType. In the example, the attribute is allowed only two values (enumeration). This means that using a datatype of xsd:string is insufficient to define the type of the employee_type attribute. Just as we did for employee_id, we must define a new type for this attribute. Just as we created a new simpleType for employee_id, the employee_type attribute defines a new type by restricting the base xsd:string type with enumeration facets:
<xsd:element >
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="employee_id" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="name" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="extn" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="dept" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="email" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="contract"/>
<xsd:enumeration value="perm"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
The general syntax for declaring attributes locally is
<xsd:attribute name="name" use="required|optional|prohibited" default/fixed="value">
<xsd:simpleType>
<xsd:restriction base="built-in type">
<xsd:facet value="value"/>
...
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
or
<xsd:attribute name="name" type="built-in type" "use="required|optional|prohibited"
default/fixed="value"/>
An attribute can also be defined globally (i.e., not inline within the complexType element definition) and then referred to within the element. When declaring attributes globally, the use parameter cannot appear within the global declaration; instead, it must be specified in the complexType element where it is referenced. The code below shows a global declaration:
<xsd:element >
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="employee_id" minOccurs="1" maxOccurs="1"/>
...
<xsd:element ref="email" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute ref="empType" use="required"/>
</xsd:complexType>
...
<xsd:attribute >
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="contract"/>
<xsd:enumeration value="perm"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
attributeGroup
If an element has several attributes, the attribute declarations can be grouped and a single reference made to the attribute group:
<xsd:element >
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="employee_id" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="name" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="extn" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="dept" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="email" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attributeGroup ref="employeeAttribute">
</xsd:complexType>
</xsd:element>
...
<xsd:attributeGroup >
<xsd:attribute type="xsd:string" use="optional" />
<xsd:attribute use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="contract"/>
<xsd:enumeration value="perm"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:attributeGroup>
Comments in XML Schema
XML Schema provides the annotation element to document the schema. An annotation element can contain two elements: the documentation element, meant for human consumption, and the appinfo element, for machine consumption:
<asd:annotation>
<xsd:documentation xml:lang="en">
The next appinfo element provides a custom instruction to the processor
</xsd:documentation>
<xsd:appinfo>
<instruction some instruction </instruction>
</xsd:appinfo>
</xsd:annotation
XML Schema cannot handle all types of validations. It cannot handle validations that require complex cross-element or -attribute values (e.g., a rule such as, "If employee_type attribute value is 'contract,' then employee_id value must be between 20,000 and 40,000"). For these types of complex validations, the appinfo element can provide instructions to another tool (e.g., an XSLT engine or Schematron) to enforce these complex constraints. An XML schema validator would validate the annotated schema against the instance document, and Schematron would validate the instance document based on the extracted instructions embedded in the appinfo elements.