Wednesday, March 29, 2023

A simple XSLT stylesheet, XML document validator

I've been thinking that, this shall be interesting to share.

Please consider following, XSLT 1.0 document transformation definition.

XML input document:

<?xml version="1.0" encoding="UTF-8"?>

<root>

  <a>2</a>

  <a>4</a>

  <a>6</a>

  <a>8</a>

  <a>10</a>

</root>

We should be able to tell, that this XML document is valid, if all XML /root/a elements within it have even numbers.

The following XSLT 1.0 stylesheet just does this XML document validation check,

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

                         xmlns:exslt="http://exslt.org/common"

                         exclude-result-prefixes="exslt"

                         version="1.0">

    <!-- An XSLT stylesheet, that checks whether values of all XML 

         input /root/a elements have even numbers (in which case, the XML input 

         document is reported as valid). -->                            

    <xsl:output method="text"/>                

    <xsl:template match="/root">

       <xsl:variable name="result">

          <xsl:for-each select="a">

             <e1><xsl:value-of select=". mod 2"/></e1>

          </xsl:for-each>

       </xsl:variable>

       <xsl:choose>

          <xsl:when test="count(exslt:node-set($result)/*[. = 0]) = count(exslt:node-set($result)/*)">

             <xsl:text>XML document is valid</xsl:text>

          </xsl:when>

          <xsl:otherwise>

             <xsl:text>XML document is in-valid</xsl:text>

          </xsl:otherwise>

       </xsl:choose>

    </xsl:template>

</xsl:stylesheet>

Please note that, within above mentioned XSLT 1.0 stylesheet, we've used an XSLT 1.0 extension function "node-set", that is supported by most of the XSLT 1.0 engines (for example, XalanJ as described here https://xalan.apache.org/xalan-j/apidocs/org/apache/xalan/lib/ExsltCommon.html). 

For the interest of readers, following is an equivalent XML Schema 1.1 validation, that solves the same problem,

<?xml version="1.0"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

   <xs:element name="root">

      <xs:complexType>

         <xs:sequence>

            <xs:element name="a" type="xs:integer" maxOccurs="unbounded"/>

         </xs:sequence>

         <xs:assert test="count(a) = count(a[. mod 2 = 0])"/>

      </xs:complexType>

   </xs:element>

</xs:schema>

Personally, speaking, I shall prefer an XML Schema 1.1 validation for this requirement, since XML Schema language is designed to do XML document validation, whereas XSLT language is designed to do an XML document transformation (but as illustrated within this blog post, the XSLT stylesheet does the job of an XML document validator as well).