Using conditional includes/static parameters in Saxon/C?

Question:

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" ><xsl:stylesheet version="3.0" ><xsl:stylesheet version="3.0" ><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>
Asked By: Daniel Haley

||

Answers:

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).

Answered By: Daniel Haley

My first test with SaxonC 11.1 and the above XSLT code and using the Python API results in the Python code

from saxonc import *

with PySaxonProcessor(license=False) as proc:
    print("Test SaxonC on Python")
    print(proc.version)
    
    xslt30proc = proc.new_xslt30_processor()
    
    result = xslt30proc.transform_to_string(stylesheet_file = 'main-sheet.xsl', source_file = 'test.xml')
         
    print(result)
    
    xslt30proc.set_parameter('inc1', proc.make_boolean_value(True))
    
    result = xslt30proc.transform_to_string(stylesheet_file = 'main-sheet.xsl', source_file = 'test.xml')
  
    print(result)
    
    xslt30proc.set_parameter('inc2', proc.make_boolean_value(True))
    
    result = xslt30proc.transform_to_string(stylesheet_file = 'main-sheet.xsl', source_file = 'test.xml')
  
    print(result)

and outputs

Test SaxonC on Python
SaxonC-HE 11.1 from Saxonica
source in transformFiletoString=test.xml stylsheet=main-sheet.xsl
<?xml version="1.0" encoding="UTF-8"?>
<doc>
   <foo/>
</doc>

source in transformFiletoString=test.xml stylsheet=main-sheet.xsl
<?xml version="1.0" encoding="UTF-8"?>
<doc>
   <foo>INCLUDE FILE 1!!!</foo>
</doc>

source in transformFiletoString=test.xml stylsheet=main-sheet.xsl
Warning at mode (unnamed)
  XTDE0540  Ambiguous rule match for /doc/foo[1]
Matches both "foo" on line 3 of
  file:/C:/Users/marti/OneDrive/Documents/xslt/blog-xslt-3-by-example/saxonc-11.1-python/conditional-include-with-static-params/test_inc2.xsl
and "foo" on line 3 of file:/C:/Users/marti/OneDrive/Documents/xslt/blog-xslt-3-by-example/saxonc-11.1-python/conditional-include-with-static-params/test_inc1.xsl
<?xml version="1.0" encoding="UTF-8"?>
<doc>
   <foo>INCLUDE FILE 2!!!</foo>
</doc>

Or just your example of setting the parameter and running the stylesheet:

from saxonc import *

with PySaxonProcessor(license=False) as proc:
    print("Test SaxonC on Python")
    print(proc.version)
    
    xslt30proc = proc.new_xslt30_processor()
    
    xslt30proc.set_parameter('inc2', proc.make_boolean_value(True))
    
    result = xslt30proc.transform_to_string(stylesheet_file = 'main-sheet.xsl', source_file = 'test.xml')
  
    print(result)

gives

Test SaxonC on Python
SaxonC-HE 11.1 from Saxonica
source in transformFiletoString=test.xml stylsheet=main-sheet.xsl
<?xml version="1.0" encoding="UTF-8"?>
<doc>
   <foo>INCLUDE FILE 2!!!</foo>
</doc>
Answered By: Martin Honnen
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.