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>
TemplateName
yet you do anxsl:apply-templates select
andxsl: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<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<xsl:apply-templates _select="{$TemplateName}"/>
does work with 9.7. - Martin Honnen