10

I wanted to use a dynamic variable name in the select statement in xslt.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
    <xsl:variable name="input" select="input/message" />
    <xsl:variable name="Name" select="'MyName'" />
    <xsl:variable name="Address" select="MyAddress" />
    <xsl:variable name="output" select="concat('$','$input')" />  <!-- This is not working -->
     <output>
       <xsl:value-of select="$output" />
     </output>
</xsl:template>

The possible values for the variable "input" is 'Name' or 'Address'. The select statement of the output variable should have a dynamic variable name based on the value of input variable. I don't want to use xsl:choose. I wanted to select the value dynamically. Please provide me a solution.

Thanks, dhinu

dhinu
  • 135
  • 1
  • 2
  • 10

2 Answers2

12

XSLT 1.0 and XSLT 2.0 don't have dynamic evaluation.

Solution for your problem:

This transformation:

 <xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output method="text"/>

 <my:values>
  <name>MyName</name>
  <address>MyAdress</address>
 </my:values>

 <xsl:template match="/">
  <xsl:variable name="vSelector"
   select="input/message"/>
  <xsl:value-of select=
   "document('')/*/my:values/*[name()=$vSelector]"/>
 </xsl:template>
</xsl:stylesheet>

when applied on the following XML document:

<input>
  <message>address</message>
</input>

produces the wanted, correct result:

MyAdress

when the same transformation is applied on this XML document:

<input>
  <message>name</message>
</input>

again the wanted, correct result is produced:

MyName

Finally: If you do not wish to use the document() function, but would go for using the xxx:node-set() extension function, then this solution (looking very similar) is what you want, where you may consult your XSLTprocessor documentation for the exact namespace of the extension:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common" >
 <xsl:output method="text"/>

 <xsl:variable name="vValues">
  <name>MyName</name>
  <address>MyAdress</address>
 </xsl:variable>

 <xsl:template match="/">
  <xsl:variable name="vSelector"
   select="input/message"/>
  <xsl:value-of select=
   "ext:node-set($vValues)/*[name()=$vSelector]"/>
 </xsl:template>
</xsl:stylesheet>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • Thank you! It worked for me.. Just want to know if there is any alternative way without using the extra namespace xmlns:my="my:my" ? – dhinu Dec 12 '10 at 05:16
  • @dhinu: Glad that my answer was useful. At SO gratitude is expressed by accepting the answer (by clicking on the check-mark next to the answer) :). You can put the `` in another file and again access it with the `document()` function. In XSLT 1.0 you generally have to use this technique. If elements are in the body of an `` or of an ``, they cannot be accessed using XPath directly and an extension function (`xxx:node-set()`) is necessary to be applied first. In XSLT 2.0 the elements inside an `` or of an `` can be accessed directly. – Dimitre Novatchev Dec 12 '10 at 06:47
  • Can you provide an example for accessing the elements in the body of an xsl:variable using the extension function (xxx:node-set()) ? (Im using XSLT 1.0) – dhinu Dec 12 '10 at 09:50
0

Beside @Dimitre's good answer, for this particular case (output string value) you could also use:

<xsl:variable name="output" 
              select="concat(substring($Name, 1 div ($input = 'Name')),
                             substring($Address, 1 div ($input = 'Address')))"/>