Using different XSLT templates depending on the parameter

What I have?

I have an ASP.NET project in which I have an XSLT file with many templates. Only one template will be used at a time, depending on the user's choice to display content on a web page. It looks something like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="TemplateName"></xsl:param> <xsl:template match="Title_Only"> ...template Title_Only body... </xsl:template> <xsl:template match="Image_Only"> ...template Image_Only body... </xsl:template> <xsl:template match="Title_And_Image"> ...template Title_And_Image body... </xsl:template> </xsl:stylesheet> 

What I need?

I want to pass the template name TemplateName as a parameter and I can apply the corresponding template to the data.

Can someone please tell me how can I achieve this?

+6
source share
3 answers

You cannot use the value of a parameter or variable in a mapping template in XSLT 1.0. Nevertheless, you can apply templates conditionally from one template, for example:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="TemplateName"/> <xsl:template match="/"> <xsl:apply templates select="something[some_condition=$TemplateName]"/> </xsl:template> </xsl:stylesheet> 

... and then just tweak the templates so that each one matches each type of node. Patterns will only apply to things that match your select expression based on a parameter.

Template Conditional Example

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="TemplateName" select="'Title_Only'" /> <xsl:template match="/"> <xsl:apply-templates select="test/val[@name=$TemplateName]" /> </xsl:template> <xsl:template match="val"> <xsl:value-of select="@name" /> </xsl:template> </xsl:stylesheet> 

Applies to this input:

 <test> <val name="Title_Only" /> <val name="Image_Only" /> <val name="Title_And_Image" /> </test> 

It produces:

 Title_Only 

... based on the value of $TemplateName . (Note that this example uses a variable, but the idea is the same.)

Separate patterns using modes

If you really need a completely different template in each case, use the modes. This style sheet:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="TemplateName" select="'Title_Only'" /> <xsl:template match="/"> <xsl:choose> <xsl:when test="$TemplateName='Title_Only'"> <xsl:apply-templates select="test/val" mode="Title_Only" /> </xsl:when> <xsl:when test="$TemplateName='Image_Only'"> <xsl:apply-templates select="test/val" mode="Image_Only" /> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="test/val" mode="Title_And_Image" /> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="val" mode="Title_Only"> <xsl:value-of select="@title" /> </xsl:template> <xsl:template match="val" mode="Image_Only"> <xsl:value-of select="@img" /> </xsl:template> <xsl:template match="val" mode="Title_And_Image"> <xsl:value-of select="@title" />/ <xsl:value-of select="@img" /> </xsl:template> </xsl:stylesheet> 

Applies to this source:

 <test> <val title="some title" img="some image"/> </test> 

It produces:

 some title 

The required template is used based on the parameter value.

+6
source

I want to pass the template name TemplateName as a parameter and it is possible to apply the corresponding template to the data.

In both XSLT 1.0 and XSLT 2.0, it is illegal to have a design such as:

 <xsl:call-template name="{$vTemplateName}"/> 

While XPath 3.0 (XSLT 3.0) introduces function elements and HOFs (higher order functions), HOFs can be emulated in previous versions of XSLT. Read the articles on the FXSL homepage for more information.

Here is a simplified example of the idea behind FXSL :

 <nums> <num>01</num> <num>02</num> <num>03</num> <num>04</num> <num>05</num> <num>06</num> <num>07</num> <num>08</num> <num>09</num> <num>10</num> </nums> 

Given this XML sample, we have two templates: one that produces the sum of all num elements, and the other creates their concatenation. We want to pass the desired operation as a parameter.

Here's how to do it (note that nothing in the source XML file tells us which operation to use):

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:param name="pOp" select="'sum'"/> <my:ops> <op>sum</op> <op>concat</op> </my:ops> <xsl:variable name="vOps" select= "document('')/*/my:ops/*"/> <xsl:template match="/"> <xsl:apply-templates select="$vOps[. = $pOp]"> <xsl:with-param name="arg1" select="/*/*"/> </xsl:apply-templates> </xsl:template> <xsl:template match="op[.='sum']"> <xsl:param name="arg1"/> <xsl:value-of select="sum($arg1)"/> </xsl:template> <xsl:template match="op[.='concat']"> <xsl:param name="arg1"/> <xsl:for-each select="$arg1"> <xsl:value-of select="."/> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

When applied to the XML document above, the desired, correct result is output:

 55 

when replacing :

  <xsl:param name="pOp" select="'sum'"/> 

from

  <xsl:param name="pOp" select="'concat'"/> 

and apply a new transformation, again you get the desired, correct result :

 01020304050607080910 

Please note :

The main (used) template can and usually will be in a separate XSLT style file and will import style sheets with templates that implement the operations. The main template does not know what operations are performed (and does not use <xsl:choose> with hardcoded names).

In fact, if templates are added or deleted from imported files, there is no need to change the main (used) template. In this programming style, the <xsl:apply-templates> command often selects execution templates that were not yet written when the main template was created.

+2
source

Include the mode attribute in <xsl: apply-templates> .

+1
source

Source: https://habr.com/ru/post/885454/


All Articles