04. Restricting numeric content

XML Schema provides various numeric data types, which can be used to constrain the allowable content of an XML element.

The xsd:integer data type allows only zero and positive or negative whole numbers. These can be further restricted by the following:

For numbers that contain a decimal point the xsd:decimal data type allows zero and positive and negative numbers, where the total number of digits is less than 18 - counting both sides of the decimal point. Long 32-bit decimal numbers are allowed by the xsd:float data type and even longer 64-bit decimal numbers are allowed by the xsd:double data type.

The XML document below has elemetns that contain a selection of numeric data, which can be constrained by schema rules:

<?xml version="1.0" encoding="UTF-8"?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="number.xsd" >
<!-- Acceptable integer content. -->
<int>123</int>
<int>-123</int>
<int>0</int>
<!-- Acceptable positive integer content. -->
<pos>123</pos>
<!-- But not 0 or -123 -->
<!-- Acceptable negative integer content. -->
<neg>-123</neg>
<neg>0</neg>
<!-- Acceptable decimal content. -->
<dec>12345.67890</dec>
<dec>0.000</dec>
<dec>-12345.67890</dec>
<!-- Acceptable float content. -->
<flt>0.12345678901234567890123456789</flt>
<flt>0.00000000000000000000000000000</flt>
<flt>-0.12345678901234567890123456789</flt>
</doc>

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- DECLARE ELEMENTS. -->
<!-- Simple types. -->
<xsd:element name="int" type="xsd:integer" />
<xsd:element name="pos" type="xsd:positiveInteger" />
<xsd:element name="neg" type="xsd:nonPositiveInteger" />
<xsd:element name="dec" type="xsd:decimal" />
<xsd:element name="flt" type="xsd:float" />
<!-- Complex types. -->
<xsd:element name="doc" type="docType"/>
<!-- DEFINE STRUCTURE. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="int" maxOccurs="unbounded"/>
<xsd:element ref="pos" maxOccurs="unbounded"/>
<xsd:element ref="neg" maxOccurs="unbounded"/>
<xsd:element ref="dec" maxOccurs="unbounded"/>
<xsd:element ref="flt" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Restricting date content

XML Schema provides various date/time data types, which can be used to constrain the allowable content of an XML element.

The xsd:time data type allows time in the usual hh:mm:ss format. optionally, a timezoe suffix can be added using the letter Z to indicate the Universal Time Clock (UTC - Greenwich Mean Time), or either +hh:mm:ss or -hh:mm:ss to indicate the difference from UTC. Date and time can be combined with the xsd:dateTime data type and CCYY-MM-DDhh:mm:ss format, which also allows the optional timezone suffix.

A year in CCYY format is allowed by xsd:gYear. The yare and month in CCYY-MM format is allowed by xsd:gYearMonth. Similarly, month and day in --MM-DD format is allowed by xsd:gMonthDay, and xsd:gDay allows the day in ----DD format.

A duration of time can be specified with xsd:duration that allows a specific format PnYnDTnHnMnS - where P, for period, is always required and T, for time, begins an optional time section. The n markers are replaced by numbers to indicate the number of Years, Days, Hours, Minutes, and Seconds in the total duration.

The XML doc below has elements that contain a selection of dates and times, which can be constrainted by schema rules:

<?xml version="1.0" encoding="UTF-8" ?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="date.xsd" >
<nytime>21:30:00-05:00</nytime> <!-- UTC -5 hours -->
<lilboy>1945-08-06T08:15:00</lilboy>
<xmasday>--12-25</xmasday>
<iditarod>P8DT22H46M02S</iditarod>
</doc>

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- DECLARE ELEMENTS. -->
<!-- Simple types. -->
<xsd:element name="nytime" type="xsd:time"/>
<xsd:element name="lilboy" type="xsd:dateTime"/>
<xsd:element name="xmasday" type="xsd:gMonthDay"/>
<xsd:element name="iditarod" type="xsd:duration"/>
<!-- Complex types. -->
<xsd:element name="doc" type="docType"/>
<!-- DEFINE STRICTURE. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="nytime" />
<xsd:element ref="lilboy" />
<xsd:element ref="xmasday" />
<xsd:element ref="iditarod" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Creating custom restrictions

The built-in XSD data types can be used as a base upon which to create your own custom data type. A separate section of code, normatlly at the start of the schema, is used to define the custom data type - so it can be used in the element declarations later.

A custom data type begins with an <xsd:simpleType> element, whose name attributes specifies a custom name. Nested within this is an <xsd:restriction> element , whose base attribute specifies the built-in data type upon which this custom data type is based.

XML Schema provides a number of "constraining facet" elements that can be nested within an <xsd:restriction> element to constrain a custom data type. One of these is the <xsd:maxInclusive> constraining facet, whose value attributes specifies an inclusive maximum allowable numeric limit.

The XML document below has elements that contain a selection of integer values, which can be constrained by a custom data type:

<?xml version="1.0" encoding="UTF-8" ?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="custom.xsd" >
<knife>10</knife> <knife>0</knife> <knife>-10</knife>
<spoon>10</spoon> <spoon>0</spoon> <spoon>-10</spoon>
</doc>

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- CUSTOM DATA TYPES. -->
<!-- Create a custom data type to restrict integer range. -->
<xsd:simpleType name="maxTenType">
<xsd:restriction base="xsd:integer">
<xsd:maxInclusive value="10"/>
</xsd:restriction>
</xsd:simpleType>
<!-- DECLARE ELEMENTS. -->
<!-- Simple types. -->
<!-- Complex types. -->
<xsd:element name="doc" type="docType"/>
<xsd:element name="knife" type="maxTenType"/>
<xsd:element name="spoon" type="maxTenType"/>
<!-- DEFINE STRUCTURES. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="knife" maxOccurs="3"/>
<xsd:element ref="spoon" maxOccurs="3"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Restricting by range

There are four constraining facets that can specify an allowable range when creating a custom data type. The top of the range can be specified with either the <xsd:maxInclusive> or <xsd:maxExclusive> facets. Using <xsd:maxInclusive> will allow up to, and including, the limit specified by its value attribute. Using <xsd:maxExclusive> on the other had, allows up to the specified limit - but not the specified value itself.

The bottom of the range can be specified with <xsd:minInclusive> or <xsd:minExclusive> facets, which behave in the same way.

Including one "max" facet and one "min" facet in the custom data type definition sets its allowable range.

Range restrictions can be applied to numeric values or date and time values. Later dates and times are greater in the range, earlier dates and times are lower in the range.

The XML document below has elements that contain a selection of time values, which ccan be constrained by a custom data type:

<?xml version="1.0" encoding="UTF-8" ?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="range.xsd" >
<afternoon>12:00:00</afternoon>
<afternoon>15:30:00</afternoon>
<afternoon>18:00:00</afternoon>
<evening>18:00:01</evening>
<evening>21:30:00</evening>
<evening>23:59:59</evening>
</doc>

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- CUSTOM DATA TYPES. -->
<!-- Create a custom data type to restrict a time range. -->
<xsd:simpleType name="pmType">
<xsd:restriction base="xsd:time">
<xsd:maxInclusive value="23:59:59"/>
<xsd:minInclusive value="12:00:00"/>
</xsd:restriction>
</xsd:simpleType>
<!-- DECLARE ELEMENTS.-->
<!-- Simple types. -->
<!-- Complex types. -->
<xsd:element name="doc" type="docType"/>
<xsd:element name="afternoon" type="pmType" />
<xsd:element name="evening" type="pmType" />
<!-- DEFINE STRUCTURE. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="afternoon" maxOccurs="3"/>
<xsd:element ref="evening" maxOccurs="3"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Restricting string length

The allowable length of a string within an XML element can be constrained by creating a custom data type, based on <xsd:string>, that uses <xsd:maxLength> and <xsd:minLength> facets.

These can specify an allowable string range, or a precise string length - where each value attribute specifies the same number, the string must contain exactly that number of characters.

The XML document below has elements that contain a selection of zip codes, which can be constrained by a custom data type:

<?xml version="1.0" encoding="UTF-8" ?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="string.xsd" >
<store>Macy's</store>
<address>151 West 34th Street, New York</address>
<zip>10001</zip>
<store>Saks Fith Avenue</store>
<address>611 5th Avenue, New York</address>
<zip>10022</zip>
<store>Bloomingdales</store>
<address>1000 3rd Avenue, New York</address>
<zip>10022</zip>
</doc>

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- CUSTOM DATA TYPES. -->
<!-- Create a custom data type to restrict string length. -->
<xsd:simpleType name="zipType">
<xsd:restriction base="xsd:string">
<xsd:minLength value="5"/>
<xsd:maxLength value="5"/>
</xsd:restriction>
</xsd:simpleType>
<!-- DECLARE ELEMENTS. -->
<!-- Simple types. -->
<xsd:element name = "store" type = "xsd:string" />
<xsd:element name = "address" type = "xsd:string" />
<!-- Complex types. -->
<xsd:element name="doc" type="docType"/>
<xsd:element name="zip" type="zipType"/>
<!-- DEFINE STRUCTURE. -->
<xsd:complexType name="docType">
<xsd:sequence maxOccurs="unbounded">
<xsd:element ref = "store" />
<xsd:element ref = "address" />
<xsd:element ref="zip"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Restricting digit length

The allowable number of digits, on each side of a decimal point, can be constrained by a custom data type that uses <xsd:fractionDigits> and <xsd:totalDigits> facets.

Whatever number is specified by the value attribute of the <xsd:fractionDigits> facet will restrict the number of digits that are allowed to the right of the decimal point.

The number specified by the value attribute of the <xsd:totalDigits> facet will restrict the total number of digits that are allowed in teh number, on both sides of the decimal point.

This provides less control than is first apparent because the number of allowable integer digits increases as the number of fractional digits decreases. For instance, with a custom decimal-based data type that allows 2 fractions and 5 total digits, 123.45, 1234.5 and 12345 would all be allowed. It would not, however, allow fractions to three decimal places or any number with more than five digits.

The XML document below has elements that contain a selection of numbers, which can be constrained by a custom data type:

<?xml version="1.0" encoding="UTF-8" ?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="digit.xsd" >
<num>0.75</num>
<num>123.45</num>
<num>9876.5</num>
<num>12345</num> <!-- Not 123456 -->
</doc>

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- CUSTOM DATA TYPES. -->
<!-- Create a custom data type to restrict digit length. -->
<xsd:simpleType name="numType">
<xsd:restriction base="xsd:decimal">
<xsd:fractionDigits value="2"/>
<xsd:totalDigits value="5"/>
</xsd:restriction>
</xsd:simpleType>

<!-- DECLARE ELEMENTS. -->
<!-- Simple types. -->
<!-- Complex types. -->
<xsd:element name="doc" type="docType"/>
<xsd:element name="num" type="numType"/>
<!-- DEFINE STRUCTURE. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="num" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Restricting by pattern

A pattern of allowable content can be specified as a regular expression, in a "pattern constraining facet" of a custom data type - the pattern it describes will be the content that is allowed.

The topic of regular expressions is vast and fills entire books. If you are familiar with any programming language you are probably already acquainted with regular expressions. For those who are new to regular expressions that table below provides an indication of the syntax used to describe allowable patterns:

Pattern Description
\d any digit
\D anything except a digit
\s any wwhitespace - space, tab, newline
\S anything except whitespace
x* zero or multiple x characters
(xy)* zero or multiple xy characters
x? one x character
(xy)? one xy characters
x+ one or more x characters
(xy)+ one or more xy characters
[xyz] one group of xyz values
[0-9] any number from zero to nine
x|y|z either x or y or z vlaue
x{3} exactly three x characters, in succession
x{3,} at least three x characters
x{3,5} at least three and at most 5 x characters
(xyz){3} exactly three xyz characters, in succession

<?xml version="1.0" encoding="UTF-8" ?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="digit.xsd" >
<num>0.75</num>
<num>123.45</num>
<num>9876.5</num>
<num>12345</num> <!-- Not 123456 -->
</doc>

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- CUSTOM DATA TYPES. -->
<!-- Create a custom data type to restrict digit length. -->
<xsd:simpleType name="ptnType">
<xsd:restriction base="xsd:decimal">
<xsd:pattern value="(\d){3}(.)(\d){2}"/>
</xsd:restriction>
</xsd:simpleType>

<!-- DECLARE ELEMENTS. -->
<!-- Simple types. -->
<!-- Complex types. -->
<xsd:element name="doc" type="docType"/>
<xsd:element name="num" type="ptnType"/>
<!-- DEFINE STRUCTURE. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="num" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Enumerating allowable content

A list of allowable values can be specified in a custom data type using <xsd:enumeration> constraining facets. Each allowable value is assigned to the value attribute of an <xsd:enumeration> element within the custom data type - so that the list of <xsd:enumeration> elements represenets the allowable content.

Where the enumerated list describes xsd:string data types the values are case-sensitive. This means that the XML element may only contain one of the listed items if it is capitalized exactly as it is specified by the value attribute of an <xsd:enumeration>. For instance, "New York" and "new york" do not match, so would cause validation to fail.

Additionally, whitespace must match - "New York" and "NewYork" do not match and would also cause validation to fail.

The XML document below has elements that contain a selection of names, which can be constrained by a custom data type:

<?xml version="1.0" encoding="UTF-8" ?>
<doc
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="enum.xsd" >
<state>Conneticut</state>
<state>Maine</state>
<state>Massachusetts</state>
<state>New Hampshire</state>
<state>Rhode Island</state>
<state>Vermont</state>
</doc>

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- CUSTOM DATA TYPES. -->
<!-- Create a custom data type to restrict by enumeration. -->
<xsd:simpleType name="newEnglandType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Conneticut"/>
<xsd:enumeration value="Maine"/>
<xsd:enumeration value="Massachusetts"/>
<xsd:enumeration value="New Hampshire"/>
<xsd:enumeration value="Rhode Island"/>
<xsd:enumeration value="Vermont"/>
</xsd:restriction>
</xsd:simpleType>
<!-- DECLARE ELEMENTS. -->
<!-- Simple types. -->
<!-- Complex types. -->
<xsd:element name="doc" type="docType"/>
<xsd:element name="state" type="newEnglandType" />
<!-- DEFINE STRUCTURE. -->
<xsd:complexType name="docType">
<xsd:sequence>
<xsd:element ref="state" maxOccurs="6"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>