Schema-Aware XSLT

Schema-Aware Validation in XSLT

A schema-aware processor loads an XSD with xsl:import-schema, and node-building instructions accept type or validation="strict | lax | preserve | strip". In Saxon 12 726,956 that is Saxon-EE only: Saxon-HE rejects xsl:import-schema with XTSE1650 xsl:import-schema requires Saxon-EE and a type attribute with XTSE1660 The @type attribute is available only with a schema-aware XSLT processor. Instead, validate as the next step. reprice.xsl is an identity transform (<xsl:mode on-no-match="shallow-copy"/> copies what no template matches) with one template that rewrites price by $pct percent; xmlschema 476 checks the result against XSD 1.1 Types's XSD 1.1:

Transforming, then validating the output with xmlschemaPython
xslt3 -s:booknest-catalog.xml -xsl:reprice.xsl pct=-110 -o:repriced.xml
~/de-venv/bin/python -c 'import xmlschema as x
e = list(x.XMLSchema11("catalog11.xsd").iter_errors("repriced.xml"))
print(len(e), "errors, first:", e[0].path, e[0].reason)'
Output
6 errors, first: /catalog/book[1]/supply/price value has to be greater than Decimal('0')

With pct=10 it is valid, and format-number() turns 20.625 into 20.62 (half to even; round() gives 20.63).


Validation

The <xsl:element>, <xsl:attribute>, <xsl:copy>, <xsl:copy-of>, <xsl:document> and <xsl:result-document> instructions (see Constructing Nodes and Basic Flow Control) can all carry type and validation attributes. This makes it possible to perform XSD validation on the generated XML during an XSLT transformation, using <xsl:import-schema> to bring a schema into scope.
ch06-import-schema.xsd, ch06-import-schema.xslXML
<?xml version="1.0" encoding="UTF-8"?>
<!-- transactions_transformed.xsd -->
<xs:schema
   xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:complexType name="rootType">
      <xs:sequence>
         <xs:element name="elem"/>
         <xs:element name="elem"/>
         <xs:element name="elem"/>
         <xs:element name="elem"/>
         <xs:element name="elem"/>
      </xs:sequence>
   </xs:complexType>
   <xs:element name="elem">
      <xs:complexType>
         <xs:simpleContent>
            <xs:extension base="xs:int">
               <xs:attribute name="id"
                                 type="xs:NMTOKEN" use="required"/>
            </xs:extension>
         </xs:simpleContent>
      </xs:complexType>
   </xs:element>
</xs:schema>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xsl:output method="xml" indent="yes"/>
   <xsl:import-schema
               schema-location="transactions_transformed.xsd"/>
   <xsl:template match="/">
      <xsl:element name="root" type="rootType">
         <xsl:element name="elem" type="xs:byte">
            <xsl:value-of select="50"/>
         </xsl:element>
         <xsl:element name="elem" validation="strip">
            <xsl:value-of select=" 'Hello' "/>
         </xsl:element>
         <xsl:element name="elem" validation="preserve">
            <xsl:value-of select=" 'Hello' "/>
         </xsl:element>
         <xsl:element name="elem" validation="strict">
            <xsl:attribute name="id">E1</xsl:attribute>
            <xsl:value-of select="100"/>
         </xsl:element>
         <xsl:element name="elem" validation="lax">
            <xsl:attribute name="id">E2</xsl:attribute>
            <xsl:value-of select="200"/>
         </xsl:element>
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>
Output
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <elem>50</elem>
   <elem>Hello</elem>
   <elem>Hello</elem>
   <elem id="E1">100</elem>
   <elem id="E2">200</elem>
</root>
The type and validation attributes must not appear together on the same instruction. type validates against a built-in type such as xs:integer, or against a type defined in the imported schema. validation performs a global validation against the declared schema, and accepts one of: <xsl:import-schema> may omit the schema-location attribute, in which case the XSD is given as child content of the element instead.

The book's examples predate XSD 1.1; the current XSD Recommendation (Part 1: Structures and Part 2: Datatypes) is 1.1, which adds features such as assertions and conditional type assignment on top of the 1.0-era constructs shown here.