I have this xsl template:
<xsl:template name="test">
I'm test
</xsl:template>
and I can call this template by calling
<xsl:call-template name="test"/>
QUESTION:
How to call xsl template by name stored in variable?
<xsl:variable name="var1" select="'test'"/>
<xsl:call-template name="$var1"/>
Instead of using xsl:call-template, try xsl:apply-templates.
<xsl:template name="test" match="test">
I'm test
</xsl:template>
<xsl:variable name="var1"><test/></xsl:variable>
<xsl:apply-templates select="$var1/*"/>
But in XSLT 3.0 you can do this much more cleanly using higher-order functions; functions become first-class values and can be bound to variables.
Related
So I'm trying to create a variable and then later on use this in my template.
This is the code I have now:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="items">
<xsl:call-template name="item" />
</xsl:template>
<xsl:template name="item">
<xsl:for-each select="item">
<xsl:variable name="currentItemTheme">
test variable
</xsl:variable>
<xsl:if test="title = name">
Showvariable: {$currentItemTheme} <br/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I have no idea why it doesn't work. My file does output the "Showvariable: ", but it just doesn't show the test values. So the for-each loops and template aren't the problem.
Is there something I'm missing? Does someone know how I get this to work?
I think you want <xsl:value-of select="$currentItemTheme"/> instead of {$currentItemTheme}, unless you are mixing the XSLT code with some other language that provides the {$currentItemTheme} syntax.
<xsl:copy-of select="$currentItemTheme"/> is another option if you build nodes in your variable and want to output them instead of just the string value as a text node.
My code looks something like this (deliberate simplification):
<xsl:template match="/">
<xsl:call-template name="call_me" />
<xsl:value-of select="$inner_variable" />
</xsl:template>
<xsl:template name="call_me">
<xsl:variable name="inner_variable" select="/*" />
</xsl:template>
Obviously this won't work because of the scope of the variable. My question is:
is there any way to either define the variable globally from the call_me template, or to access this local variable from the parent (calling template) scope?
EDIT: The variable is not a XML tree fragment, but a node-set processed by C# functions. So I really need to access the variable.
Thanks!
If you want to have a variable with the result of the called template, do:
<xsl:template match="/">
<xsl:variable name="result">
<xsl:call-template name="call_me" />
</xsl:variable>
...
</xsl:template>
This assumes the called template returns some kind of result, for example:
<xsl:template name="call_me">
<xsl:value-of select="some-node" />
</xsl:template>
From my root template for unique account value, call goes to trans template were in the input xml I will have multiple nodes, my requirement is that once the call goes from root template to trans template, if a match of accountId found in between multiple elements, account details template is called only once, irrespective of other match found. I need a solution for above requirement.
input sample :
<elements><accountId>1</accountId></elements>
<elements><accountId>1</accountId></elements>
<elements><accountId>2</accountId></elements>
<elements><accountId>2</accountId></elements>
<elements><accountId>3</accountId></elements>
The below line should be wrapped under some code so its called only once
<xsl:call-template name="Account_details" />
Below is my complete code for xsl
<xsl:template match="/">
<xsl:variable name="unique-accounts" select="//*/*/*/accountId/text()[generate-id()=generate-id(key('account-by-id', .)[1])]"/>
<xsl:for-each select="$unique-accounts">
<xsl:variable name="currentValue" select="current()"/>
<xsl:apply-templates select="//trans">
<xsl:with-param name="passCurrentValue" select="$currentValue"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="trans">
<xsl:param name="passCurrentValue" />
<xsl:variable name="booleanValue" select="true()"/>
<xsl:for-each select="elements">
<xsl:if test="$passCurrentValue=/*/*/accountId">
<xsl:if test="$booleanValue">
<xsl:call-template name="Account_details" />
<xsl:variable name="booleanValue" select="false()"></xsl:variable>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="Account_details">
.............
</xsl:template>
With the code
<xsl:template match="/">
<xsl:variable name="booleanCheck" select="true"></xsl:variable>
the variable booleanCheck is a node-set (XSLT 1.0) or sequence of elements named true below the document node /. So unless your XML input has a root element named true the value is an empty node-set respectively empty sequence. If you want to select a boolean value then use <xsl:variable name="booleanValue" select="true()"/>. See http://www.w3.org/TR/xpath/#function-true. Then you can test <xsl:if test="$booleanValue">. That should explain how to use boolean values, whether that fits into your context I am not sure.
In XSLT 1.0, what is the shortest/cleanest/recommended way to pass the current context node to a called template and have that node become the context node inside the called template?
It would be nice (it would, right?) if a template with no xsl:param and called by an empty call-template would simply pick up the caller's context node, but the best I can think of is this:
<xsl:call-template name="sub">
<xsl:with-param name="context" select="." />
</xsl:call-template>
with
<xsl:template name="sub">
<xsl:param name="context" />
<xsl:for-each select="$context">
</xsl:for-each>
</xsl:template>
It would be nice (it would, right?) if a template with no xsl:param
and called by an empty call-template would simply pick up the
caller's context node.
This is exactly how xsl:call-template is defined in the W3C XSLT 1.0 (and 2.0) specification, and implemented by any compliant XSLT processor.
Here is a small example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="a">
<xsl:call-template name="currentName"/>
</xsl:template>
<xsl:template name="currentName">
Name: <xsl:value-of select="name(.)"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<a/>
</t>
the wanted, correct result is produced:
Name: a
Just otherway of explaining what Dimitre said.
When you call a template from a node, you are already there in that node,
example:
assume this code:
<xsl:template match="MyElement">
<xsl:call-template name="XYZ"/>
</xsl:template>
<xsl:template name="XYZ>
<xsl:value-of select="."/>
</xsl>
The above code is as good as writing:
<xsl:template match="MyElement">
<xsl:value-of select="."/>
</xsl:template>
You can use for-each loop in the called template as well. :)
But just be sure where you exactly are ..
I want to create a variable like that :
<xsl:variable name="mytree" >
<foos>
<foo>bar</foo>
<foo>bar</foo>
<foo>bar</foo>
<foo>bar</foo>
<foos>
</xsl:variable>
to use it like in :
<xsl:call-template name="myTemplate">
<xsl:with-param name='aTree' select='$mytree' />
</xsl:call-template>
<xsltemplate name="myTemplate">
<xsl:param name="aTree" />
[My code that treat $aTree like a Tree]
</xsl:template>
My question is : is it possible to create a Tree variable and How?
To achieve this, you probably need to make use of an extension function, namely the node-set function, which returns a set of nodes from a result tree fragment.
First you would need to define the namespace for the extension functions like so
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
In this case, I am using the Microsoft extension functions, but others are available depending on which platform you are using. (http://exslt.org/common is another common one for non-Microsoft platforms).
Then, you can access the elements in your variable like so (as an example)
<xsl:apply-templates select="msxsl:node-set($aTree)/foos/foo"/>
Putting this altogether in a simple example gives you this
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:variable name="mytree">
<foos>
<foo>bar1</foo>
<foo>bar2</foo>
<foo>bar3</foo>
<foo>bar4</foo>
</foos>
</xsl:variable>
<xsl:template match="/">
<xsl:call-template name="myTemplate">
<xsl:with-param name="aTree" select="$mytree"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="myTemplate">
<xsl:param name="aTree"/>
<newfoos>
<xsl:apply-templates select="msxsl:node-set($aTree)/foos/foo"/>
</newfoos>
</xsl:template>
<xsl:template match="foo">
<newfoo>
<xsl:value-of select="text()"/>
</newfoo>
</xsl:template>
</xsl:stylesheet>
When run, this simply outputs the following result:
<newfoos>
<newfoo>bar1</newfoo>
<newfoo>bar2</newfoo>
<newfoo>bar3</newfoo>
<newfoo>bar4</newfoo>
</newfoos>
Given this example, there is no reason why you can't dynamically create your myTree variable first.