8.6. Implementation-defined types and facets
Starting with version 1.1, additional simple types and facets may be defined and supported by a particular XML Schema implementation.
8.6.1. Implementation-defined types
An implementation can choose to support a set of primitive simple types in addition to those built into XML Schema (described in Chapter 11).
Suppose that an implementation defines a special primitive type ordinalDate that represents an ordinal date: a year, followed by a hyphen, followed by a number from 001 to 366 indicating the day of the year. Although an ordinal date value could be represented as a string, it may be beneficial to promote it to its own primitive type if it has special considerations for ordering or validation of its values, or special operations that can be performed on it (for example, subtracting two ordinal dates to get a duration).
A schema author can use an implementation-defined type just like a built-in type, except that it will be in a different namespace defined by the implementation. The schema in Example 8–22 contains two references to the ordinalDate type, which is in the hypothetical http://example.org/extensions namespace. The anyOrdinalDate element declaration refers to the type directly by its qualified name. The OrdinalDateIn2011 user-defined simple type is a restriction of ordinalDate using bounds facets to specify a range of allowed values.
Example 8–22. Using an implementation-defined type
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ext="http://example.org/extensions"> <xs:element name="anyOrdinalDate" type="ext:ordinalDate"/> <xs:element name="recentOrdinalDate" type="OrdinalDateIn2011"/> <xs:simpleType name="OrdinalDateIn2011"> <xs:restriction base="ext:ordinalDate"> <xs:minInclusive value="2011-001"/> <xs:maxInclusive value="2011-365"/> </xs:restriction> </xs:simpleType> </xs:schema>
8.6.2. Implementation-defined facets
Implementation-defined facets might specify additional constraints on the valid values, or even signal to the processor how to process the value. An example is the Saxon processor’s preprocess facet which allows you to specify an XPath expression that transforms the value in some way before validation.
In Example 8–23, the saxon:preprocess facet appears among the children of restriction. You can tell that it is an implementation-defined facet because it is in a different namespace, http://saxon.sf.net/. This particular example is telling the processor to convert the value to upper case before validating it against the enumeration facets. It is essentially implementing a case-insensitive enumeration.
Example 8–23. Using the Saxon preprocess facet
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/"> <xs:simpleType name="SMLXSizeType"> <xs:restriction base="xs:token"> <saxon:preprocess action="upper-case($value)"/> <xs:enumeration value="SMALL"/> <xs:enumeration value="MEDIUM"/> <xs:enumeration value="LARGE"/> <xs:enumeration value="EXTRA LARGE"/> </xs:restriction> </xs:simpleType> </xs:schema>
Implementation-defined facets can apply to the XML Schema built-in types (and user-defined restrictions of them); they can also apply to any implementation-defined types such as the ordinalDate example type described in the previous section.
While implementation-defined types and facets can be useful, they do affect the portability of your schema. With the schema in Example 8–23, if you try to validate a document that contains lower-case “small” for a size, it would be valid when using Saxon but not when using a different implementation. Therefore, implementation-defined facets should be used only in controlled situations. Section 23.5.3 on p. 642 provides more information on how to make your schemas more portable across implementations when using implementation-defined types and facets.