0
votes

I encountered a strange issue while I was trying to build an XSLT stylesheet that takes a parameter and applies appropriate templates based on a string value of that parameter. Here is my code:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    version="3.0" default-mode="s">

    <xsl:mode name="s" streamable="yes" on-no-match="shallow-skip"/>
    <xsl:mode name="ns" streamable="no"/>

    <xsl:output method="xml" indent="yes"/>

    <xsl:param name="TemplateName" as="xs:string"/>

    <xsl:template match='/' mode="s">
        <File>
            <xsl:apply-templates mode="s"/>
        </File>
    </xsl:template>

    <xsl:template match="Employee">
        <xsl:choose>
            <xsl:when test="$TemplateName = 'Template1'">
                <xsl:apply-templates select="Template1"/>
            </xsl:when>
            <xsl:when test="$TemplateName = 'Template2'">
                <xsl:apply-templates select="Template2"/>
            </xsl:when>
            <xsl:when test="$TemplateName = 'Template3'">
                <xsl:apply-templates select="Template3"/>
            </xsl:when>
            <xsl:when test="$TemplateName = 'Template4'">
                <xsl:apply-templates select="Template4"/>
            </xsl:when>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="Template1">
        <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="Template2">
        <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="Template3">
        <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="Template4">
        <xsl:copy-of select="."/>
    </xsl:template>

</xsl:stylesheet>

Everything works without any issues as long as I have only 3 "xsl:when" conditions in my "xsl:choose" code. As soon as I add the 4th condition:

<xsl:when test="$TemplateName = 'Template4'">
    <xsl:apply-templates select="Template4"/>
</xsl:when>

I receive the following error:

Template rule is declared streamable but it does not satisfy the streamability rules. * There is more than one consuming operand: {xsl:apply-templates} on line 25, and {xsl:apply-templates} on line 28

I am using Saxon-EE 9.7.0.19.

What is causing this issue? Is there any other way to apply templates dynamically based on input parameter?

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <Employee>
        <Template1>SomeData1</Template1>
        <Template2>SomeData2</Template2>
        <Template3>SomeData3</Template3>
        <Template4>SomeData4</Template4>
    </Employee>
    <Employee>
        <Template1>SomeData1</Template1>
        <Template2>SomeData2</Template2>
        <Template3>SomeData3</Template3>
        <Template4>SomeData4</Template4>
    </Employee>
    <Employee>
        <Template1>SomeData1</Template1>
        <Template2>SomeData2</Template2>
        <Template3>SomeData3</Template3>
        <Template4>SomeData4</Template4>
    </Employee>
</Root>
1
I am kind of confused that you use a parameter named TemplateName yet you do an xsl:apply-templates select and xsl:template match based on the name which seems a child element selection. Anyway, XSLT 3 knows static parameters you can use with shadow attributes so try whether <xsl:param name="TemplateName" as="xs:string" static="yes"/> and a single <xsl:apply-templates _select="{$TemplateName}"/> works. As an alternative, you could use <xsl:apply-templates select="*[name() = $TemplateName]"/>. - Martin Honnen
Keep in mind that static parameters need to be set from the API in a different way than normal ones so if you run Saxon with code you will need to use e.g.saxonica.com/html/documentation9.7/javadoc/net/sf/saxon/s9api/… - Martin Honnen
Thank you @MartinHonnen. I added the input XML to my original question. I ended up using your second solution, i.e. <xsl:apply-templates select="*[name() = $TemplateName]"/> Sorry, names of my parameter and templates might have been a little confusing indeed. Would you mind adding your comment as an answer so that I can mark it as the solution? - ajmaks
I have tried your code with the current stable release 9.9 and there it works so if you can move to that version. 9.7 is too old anyway as 9.8 was the first release to implement the final XSLT 3 spec. - Martin Honnen
It seems using a static parameter and then a shadow attribute <xsl:apply-templates _select="{$TemplateName}"/> does work with 9.7. - Martin Honnen

1 Answers

0
votes

Please try it on a more recent Saxon release (9.9 or 10.0). The streaming capabilities in the product advanced considerably since 9.7 was released back in 2015. (The XSLT 3.0 spec wasn't even published then.)