XML Tutorial · Validation · Lesson 10 of 28
XML Schema: Advanced Types
Restrictions and facets, enumerations and patterns, named and derived types, keys and references, and target namespaces.
Restricting simple types with facets
<xs:simpleType name="Sku">
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{3}-[0-9]{2}"/> <!-- regular expression -->
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="Currency">
<xs:restriction base="xs:string">
<xs:enumeration value="EUR"/>
<xs:enumeration value="GBP"/>
<xs:enumeration value="USD"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="Price">
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0"/>
<xs:fractionDigits value="2"/>
</xs:restriction>
</xs:simpleType>
Other facets: minLength/maxLength, length, maxInclusive, minExclusive, totalDigits, whiteSpace.
Named types, extension and keys
- Define a
xs:complexType name="Address"once and reuse it for billing and delivery addresses. - Extension derives a type that adds elements or attributes; restriction narrows one.
xs:key/xs:keyref/xs:uniqueenforce identity constraints with XPath, like primary and foreign keys.targetNamespaceputs the schema's elements in a namespace; withelementFormDefault="qualified"local elements are namespaced too (almost always what you want).
from lxml import etree
schema = etree.XMLSchema(etree.fromstring(b"""
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:example:shop" xmlns="urn:example:shop" elementFormDefault="qualified">
<xs:simpleType name="Sku">
<xs:restriction base="xs:string"><xs:pattern value="[A-Z]{3}-[0-9]{2}"/></xs:restriction>
</xs:simpleType>
<xs:simpleType name="Currency">
<xs:restriction base="xs:string">
<xs:enumeration value="EUR"/><xs:enumeration value="GBP"/><xs:enumeration value="USD"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="catalog">
<xs:complexType>
<xs:sequence>
<xs:element name="product" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="sku" type="Sku" use="required"/>
<xs:attribute name="currency" type="Currency" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:unique name="uniqueSku">
<xs:selector xpath="s:product" xmlns:s="urn:example:shop"/>
<xs:field xpath="@sku"/>
</xs:unique>
</xs:element>
</xs:schema>"""))
tests = {
"ok": '<product sku="TEA-01" currency="EUR"/><product sku="MUG-07" currency="GBP"/>',
"bad pattern": '<product sku="tea-1" currency="EUR"/>',
"bad enum": '<product sku="TEA-01" currency="BTC"/>',
"duplicate sku": '<product sku="TEA-01" currency="EUR"/><product sku="TEA-01" currency="USD"/>',
}
for name, body in tests.items():
doc = etree.fromstring(f'<catalog xmlns="urn:example:shop">{body}</catalog>'.encode())
ok = schema.validate(doc)
print(f"{name}: {'valid' if ok else 'invalid - ' + schema.error_log[0].message}")
Output
ok: valid
bad pattern: invalid - Element '{urn:example:shop}product', attribute 'sku': [facet 'pattern'] The value 'tea-1' is not accepted by the pattern '[A-Z]{3}-[0-9]{2}'.
bad enum: invalid - Element '{urn:example:shop}product', attribute 'currency': [facet 'enumeration'] The value 'BTC' is not an element of the set {'EUR', 'GBP', 'USD'}.
duplicate sku: invalid - Element '{urn:example:shop}product': Duplicate key-sequence ['TEA-01'] in unique identity-constraint '{urn:example:shop}uniqueSku'.XSD 1.0 vs 1.1
XSD 1.1 (2012) adds assertions (xs:assert test="@end ge @start"), conditional type assignment and
xs:all with repeats. libxml2 (lxml, PHP) and the JDK's built-in validator support 1.0 only; for 1.1 use
Saxon-EE or Xerces-J's 1.1 build, or express cross-field rules in Schematron.
Test yourself
Which XSD feature works like a database primary key across elements?
xs:key (or xs:unique)xs:patternxs:sequencexs:any
Show answer
Answer: xs:key (or xs:unique)
Identity constraints select elements with XPath and require their field values to be unique.