node.jsxsltxhtmlsaxon-js

Does Saxon-js perform XML syntax checking on a xsl:param?


I run this XSL script thru Saxon-js. It updates a cost field on the main input XHTML using the XML received in the transform call using the stylesheetParams. All good. The problem is that no syntax checking is done on the param-XML (you can see what it looks like in the commented-out line). It is on the XHTML and the transform will generate an error but not on the param-XML. It just allows it to enter and then the key-function just doesn't update the XHTML. Is there a way to do the checking for properly formed XML parameter in the same transform call, or do I have to use 2 transform calls: call transform on the param-XSL to syntax-check, then call this main transform to update the XHTML?

<xsl:stylesheet version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">
  <xsl:output method="html" omit-xml-declaration="yes" encoding="UTF-8" include-content-type="no"/>
  <xsl:param name="cost-data"/>
    <!-- <supplier><product><key>3</key><pcost uptype="1"><key>21341</key><cost>12.99</cost></pcost></product></supplier> -->
    <!-- </xsl:param> -->
  
  <xsl:key name="cost" match="product/pcost[@uptype = 1]/cost" use="'cost' || ancestor::product/key"/>
  
  <xsl:mode on-no-match="shallow-copy"/>
        
  <xsl:template match="td[@name][key('cost', @name, fn:parse-xml($cost-data))]/text()">{key('cost', ../@name, fn:parse-xml($cost-data))}%</xsl:template>

<xsl:template match="/" name="xsl:initial-template">
  <xsl:next-match/>
</xsl:template>
</xsl:stylesheet>

Solution

  • If your stylesheet code is

    <xsl:param name="cost-data">
        <supplier><product><key>3</key><pcost uptype="1"><key>21341</key>     
           <cost>12.99</cost></pcost></product></supplier>
    </xsl:param>
    

    then that's well-formed XML and no error should be reported.

    However, fn:parse-xml($cost-data) is wrong. The value of the parameter is a node tree, not a string, and fn:parse-xml() expects lexical XML in a string. The effect of calling fn:parse-xml() on this node tree will be to first atomize the node, producing the untyped atomic value "32134112.99", and then attempt to parse this string "32134112.99" as lexical XML, which should fail.

    To avoid confusion like this it's good practice to always declare the expected type of your parameters, for example as="xs:string" or as="document-node()".

    If you want the default value of $cost-data to be a string containing lexical XML, try

    <xsl:param name="cost-data" as="xs:string"><![CDATA[
        <supplier><product><key>3</key><pcost uptype="1"><key>21341</key>     
           <cost>12.99</cost></pcost></product></supplier>
    ]]></xsl:param>
    

    all on one line without whitespace (or if you need whitespace for readability, put it before a ">" delimiter).

    Note: the literal answer to your question is: No. Saxon-JS doesn't perform this checking. The XML parser performs it, long before Saxon-JS gets to see the data.