XSLT call template with dynamic QName?

I searched all around to find a solution to my problem, but I had more questions ...

consider the following XML:

<dynamicStuff> <dyn id="name1">...</dyn> <dyn id="name2">...</dyn> <dyn id="name3">...</dyn> <dyn id="name4">...</dyn> </dynamicStuff> 

and suppose I have an XSLT file as follows:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template name="name1"> ... </xsl:template> <xsl:template name="name2"> ... </xsl:template> <xsl:template name="name3"> ... </xsl:template> <xsl:template name="name4"> ... </xsl:template> </xsl:stylesheet> 

What I want to do is from the SECOND XSLT file, which dynamically determines which template to call using the following:

 <xsl:variable name="templateName"> <xsl:value-of select="dyn/@id"/> </xsl:variable> <xsl:call-template name="$templateName"/> 

Unfortunately, this does not work, believe me, when I say that I have tried many different things, although it sounds so simple that it does not work either ...

Did I miss something?

Edit:

I have successfully completed the following:

 <xsl:template name="staticName"> <xsl:param name="id" /> <xsl:if test="$id = 'name1'">....</xsl:if> <xsl:if test="$id = 'name2'">....</xsl:if> ... </xsl:template> 

The call this way:

 <xsl:call-template name="staticName"> <xsl:with-param name="id" select="@id"/> </xsl:call-template> 

A needle to say how inconvenient it is ... first of all, my code will be attached to this staticName (imagine that I need to make this call in a dozen files) ... second I will have a bunch of (un) related content inside the same same template when it can be more divided ... a nightmare for updating the uu system

He does what I want, but not the way I need ...

Thanks in advance for any light on this!

+6
source share
5 answers

From http://www.w3.org/TR/xslt#named-templates

The value of the name attribute is a QName that expands as described in [ 2.4 Qualified Names ].

This means that this is not an expression, but AVT.

Explicit xsl:call-template instructions are good, whether by logical instructions or pattern matching, for example:

 <xsl:template match="dyn[@id='name1']" mode="dynamic"> <xsl:call-template name="name1"/> </xsl:template> 

Another approach is called template links ...

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="vTemplate" select="document('')/*/xsl:template"/> <xsl:template match="dyn"> <xsl:apply-templates select="$vTemplate[@name = current()/@id]"/> </xsl:template> <xsl:template match="xsl:template[@name='name1']" name="name1"> one </xsl:template> <xsl:template match="xsl:template[@name='name2']" name="name2"> two </xsl:template> <xsl:template match="xsl:template[@name='name3']" name="name3"> three </xsl:template> <xsl:template match="xsl:template[@name='name4']" name="name4"> four </xsl:template> </xsl:stylesheet> 

Conclusion:

  one two three four 


Note. . Since this method uses document('') to process XSLT, and not the source XML file, the source document is not available in the named templates. However, you can explicitly pass current() as a parameter to the templates, if necessary:
  <xsl:template match="dyn"> <xsl:apply-templates select="$vTemplate[@name = current()/@id]"> <xsl:with-param name="current" select="current()"/> </xsl:apply-templates> </xsl:template> 

If necessary, $current can be used to access the source document:

  <xsl:template match="xsl:template[@name='name1']" name="name1"> <xsl:param name="current"/> <xsl:value-of select="$current/@id"/> <xsl:text> becomes one</xsl:text> </xsl:template> 

If necessary, $current can be restored as the current node using for-each :

 <xsl:template match="xsl:template[@name='name2']" name="name2"> <xsl:param name="current"/> <xsl:for-each select="$current"> <xsl:value-of select="@id"/> <xsl:text> becomes two</xsl:text> </xsl:for-each> </xsl:template> 
+6
source

If you have only a finite number of possible templates, will it work with the xsl if construct to choose what to do in the main template?

 <xsl:if test="$templateName = 'name1'"> <xsl:call-template name="name1"/> </xsl:if> 
+1
source

Usually, when someone tries to do this, it means that they are not aware of the full power of xsl: apply-templates. The way to do dynamic dispatch in XSLT is to use xsl: apply-templates. For example, for the indicated problem, set pattern rules such as

 <xsl:template match="dyn[@id='name1']">...</xsl:template> <xsl:template match="dyn[@id='name2']">...</xsl:template> <xsl:template match="dyn[@id='name3']">...</xsl:template> 

and then use <xsl:apply-templates select="dyn"/> to submit.

+1
source

What you are trying is not directly possible, but why not just map the id attribute value first? If you absolutely need the indirectness of the called template, then call it from the template that matches the id (see below name4 ):

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <t><xsl:apply-templates select="dynamicStuff/dyn"/></t> </xsl:template> <!-- match on attribute value --> <xsl:template match="dyn[@id='name1']">name1</xsl:template> <xsl:template match="dyn[@id='name2']">name2</xsl:template> <xsl:template match="dyn[@id='name3']">name3</xsl:template> <xsl:template match="dyn[@id='name4']"> <xsl:call-template name="name4"/> </xsl:template> <!-- named templates --> <xsl:template name="name1">name1</xsl:template> <xsl:template name="name2">name2</xsl:template> <xsl:template name="name3">name3</xsl:template> <xsl:template name="name4">name4</xsl:template> </xsl:stylesheet> 

Input:

 <dynamicStuff> <dyn id="name1">...</dyn> <dyn id="name2">...</dyn> <dyn id="name3">...</dyn> <dyn id="name4">...</dyn> </dynamicStuff> 

Conclusion:

 <t>name1name2name3name4</t> 
0
source

If you use the old Saxon-B or newer Saxon-PE or Saxon-EE as an XSLT processor, you can use the Saxon extension to achieve dynamic template calls:

 <xsl:variable name="templateName"> <xsl:value-of select="dyn/@id"/> </xsl:variable> <saxon:call-template name="{$templateName}"/> 

Remember to declare the saxon namespace in the xsl-stylesheet element:

 <xsl:stylesheet xmlns:saxon="http://saxon.sf.net/" [...] > 
0
source

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


All Articles