7

I'm stuck with a small problem.

The XSL-File:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0"  
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"> 
<xsl:template match="/"> 


<xsl:variable name="unumericValue" select="10" />
<xsl:variable name="uanotherValue" select="8" />



<xsl:for-each select="/root/try">
<xsl:value-of select="var" />
<xsl:variable name="min"><xsl:value-of select="@minimum" /></xsl:variable>
<xsl:value-of select="@type" />
<xsl:variable name="referenceName"><xsl:value-of select='concat("u",var)' /></xsl:variable>
<xsl:value-of select="$referenceName" />
<xsl:if test='$referenceName > $min'>
<p>Do something.</p>
</xsl:if>
</xsl:for-each>

</xsl:template>
</xsl:stylesheet>

The XML File:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="q1.xsl"?>
<root>
<try type="compare" minimum="9">
<var>numericValue</var>
<something>...</something>
</try>

<try type="compare" minimum="10">
<var>anotherValue</var>
<something>...</something>
</try>
</root>

As you can see the XML file has two var-Elements which should match to the variables in the XSLT-File. However I don't know which Syntax is correct. $referenceName is just the name of the variable which I want to use. But I don't know how to reference the name to the existing variable.

1

3 Answers 3

11

$referenceName isn't a reference to the variable with the name "unumericValue" or otherwise. It's just the string value "unumericValue", etc. So that will never be greater than $min. However, with a little extra work, there is a trick to find a variable by its name:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:variable name="numericValue" select="10" />
  <xsl:variable name="anotherValue" select="8" />
  <xsl:variable name="vars" select="document('')/*/xsl:variable" />

  <xsl:template match="/">
    <xsl:variable name="referenceName" select="'numericValue'" />
    <xsl:variable name="referenceValue" select="$vars[@name = $referenceName]/@select" />
    Reference value: <xsl:value-of select="$referenceValue" />
  </xsl:template>
</xsl:stylesheet>

One big limitation to note here is that this will only work for variables that are a constant numeric value.

Here's a way to simulate variables with constant string values:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:v="variables-node"
>
  <v:variables>
    <v:variable n="numericValue" value="10" />
    <v:variable n="nonNumericValue" value="Hello World" />
  </v:variables>
  <xsl:variable name="vars" select="document('')//v:variables/v:variable" />

    <xsl:template match="/">
      <xsl:variable name="referenceName" select="'nonNumericValue'" />
      <xsl:variable name="referenceValue" select="$vars[@n = $referenceName]/@value" />
      <xsl:value-of select="concat('The variable with the name ', $referenceName, ' has the value ', $referenceValue)"/>
    </xsl:template>
</xsl:stylesheet>

And lastly, a way to simulate variables with calculated values:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exslt="http://exslt.org/common"
>

  <xsl:variable name="varsRaw">
    <var n="computedValue" value="{concat('2 + 4 is ', 2 + 4)}" />
    <var n="computedNumber" value="{22 div 7}" />
  </xsl:variable>
  <xsl:variable name="vars" select="exslt:node-set($varsRaw)/var" />

    <xsl:template match="/">
      <xsl:variable name="referenceName" select="'computedValue'" />
      <xsl:variable name="referenceValue" select="$vars[@n = $referenceName]/@value" />
      <xsl:value-of select="concat('The variable with the name ', $referenceName, ' has the value ', $referenceValue)"/>

      <xsl:value-of select="'     '"/>

      <xsl:variable name="referenceName2" select="'computedNumber'" />
      <xsl:variable name="referenceValue2" select="$vars[@n = $referenceName2]/@value" />
      <xsl:value-of select="concat('The variable with the name ', $referenceName2, ' has the value ', $referenceValue2)"/>
    </xsl:template>
</xsl:stylesheet>

The last approach is probably actually the most orthodox, but requires the XSLT processor-dependent (at least in XSLT 1.0) node-set() function.

Sign up to request clarification or add additional context in comments.

Comments

6

By the way, don't do this:

<xsl:variable name="min"><xsl:value-of select="@minimum" /></xsl:variable>

when you could do this:

<xsl:variable name="min" select="@minimum" />

It's not only verbose, it's also inefficient - there's no need to copy the data and construct a new tree, which is a very expensive operation, when all you want is a reference to an existing node.

1 Comment

Of course you're right. It's also a lot easier and shorter to write :)
1

As with most programming languages, XSLT variable names aren't accessible at run-time. The variable might not even exist at run-time - the optimizer is allowed to play all sorts of tricks, like inlining all references to the variable at the point where the variable is used.

The best approach is to have a variable with a standard name, and give it XML content. The element and attribute names in the XML are accessible at run-time, unlike the variable names.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.