pythonxsltsaxonxslt-3.0saxon-c

Using conditional includes/static parameters in Saxon/C?


I'm trying to use XSLT conditional includes/static parameters with Saxon/C HE, but I'm getting the following error:

Error 
  Parameter $some_param cannot be supplied dynamically because it is declared as static

To reproduce, I've used an example from a couple of answers I added a few years ago. (Here and here.)

In both of those answers I used the java version 9.7 of Saxon-HE from the command line without issue. I also tested again using java version 10.5 of HE from the command line. Again no issues.

However, if I try to run this example from Python (3.8) using Saxon/C 1.2.1 running with Saxon-HE 9.9.1.5C I get the error above.

Does anyone else have experience with static params in XSLT 3.0 and Saxon/C (especially with Python) that can provide guidance?

Test code...

XML Input (test.xml)

<doc>
    <foo/>
</doc>

Python

import saxonc

saxon_proc = saxonc.PySaxonProcessor(license=False)

print(f"Processor version: {saxon_proc.version}")

xsltproc = saxon_proc.new_xslt30_processor()

# noinspection PyArgumentList
xsltproc.set_parameter("inc2", saxon_proc.make_boolean_value(True))

results = xsltproc.transform_to_string(source_file="test.xml", stylesheet_file="test_main.xsl")

if results:
    print(results)

saxon_proc.release()

Main XSLT 3.0 (test_main.xsl)

<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="xs">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:param name="inc1" as="xs:boolean" select="false()" 
        static="yes" required="no"/>
    <xsl:param name="inc2" as="xs:boolean" select="false()" 
        static="yes" required="no"/>

    <xsl:include href="test_inc1.xsl" use-when="$inc1"/>
    <xsl:include href="test_inc2.xsl" use-when="$inc2"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>

First possible included XSLT 3.0 (test_inc1.xsl)

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:template match="foo">
        <xsl:copy>INCLUDE FILE 1!!!</xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>

Second possible included XSLT 3.0 (test_inc2.xsl)

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:template match="foo">
        <xsl:copy>INCLUDE FILE 2!!!</xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>

Expected Output (this is what I get using java Saxon-HE from the command line (shown below))

<doc>
   <foo>INCLUDE FILE 2!!!</foo>
</doc>

Actual Output

Processor version: Saxon/C 1.2.1 running with Saxon-HE 9.9.1.5C from Saxonica
Error 
  Parameter $inc2 cannot be supplied dynamically because it is declared as static

Working command line:

java -cp "saxon-he-10.5.jar" net.sf.saxon.Transform -s:"test.xml" -xsl:"test_main2.xsl" inc2="true"

I should also note that I get the same error when trying to use a shadow attribute (command line still works using the command line arg inc_number="2"):

<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="xs">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="inc_number" as="xs:string" select="'1'" static="yes" required="no"/>

    <xsl:include _href="test_inc{$inc_number}.xsl"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>

Solution

  • From @ond1 (O'Neil Delpratt - Saxonica)...

    Hi, unfortunately it is not currently possible to set the static parameters in the current version, but I have added this feature which will be available in the next release.

    So until setting static params is supported, I'm going to use two different "main" XSLTs; each one including the desired stylesheet. Another option is to transform the XSLT before executing it, but the two separate "main"'s is what I'm already doing anyway.

    Also, once setting static params is supported I'll update this answer with a full working example.


    UPDATE

    Martin confirmed this was fixed in SaxonC 11.1. I was also able to test/confirm with SaxonC 12.

    Here are updated Python examples that use the XSLT from my original question.

    These were tested with SaxonC-HE 12 installed using pip from pypi.

    Example #1

    from saxonche import PySaxonProcessor
    
    saxon_proc = PySaxonProcessor(license=False)
    
    print(f"Processor version: {saxon_proc.version}")
    
    xsltproc = saxon_proc.new_xslt30_processor()
    
    xsltproc.set_parameter("inc2", saxon_proc.make_boolean_value(True))
    
    results = xsltproc.transform_to_string(source_file="test.xml", stylesheet_file="test_main.xsl")
    
    if results:
        print(results)
    

    Example #2 (shadow attribute)

    from saxonche import PySaxonProcessor
    
    saxon_proc = PySaxonProcessor(license=False)
    
    print(f"Processor version: {saxon_proc.version}")
    
    xsltproc = saxon_proc.new_xslt30_processor()
    
    xsltproc.set_parameter("inc_number", saxon_proc.make_string_value("2"))
    
    results = xsltproc.transform_to_string(source_file="test.xml", stylesheet_file="test_main2.xsl")
    
    if results:
        print(results)
    

    I'm not using with to manage context in my examples, but the pypi documentation recommends it (could not find this mentioned in the Saxonica documentation).