Why aren't my XSLT variables substituting their values?

brabster picture brabster · Mar 11, 2009 · Viewed 7.5k times · Source

I am trying to use XSLT variables and not having much success, hopefully I'm just doing something dumb.

I have the following code snippet:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xalan="http://xml.apache.org/xslt"
  version="1.0">

    <xsl:template match="/">
      <xsl:variable name="config" select="query/@config"></xsl:variable>

so I expect there to be a variable 'config' set to the value of the 'config' attribute of my top-level element 'query'.

I then try to use the variable later in my stylesheet, for example:

<a href="localhost/test?go">
    {$config}
</a>

but the output I see in my output HTML document is:

<a href="localhost/test?go">
    {$config}
</a>

so the value has not been substituted as I would have expected.

I think this is pretty much the simplest case there could be, so I'm doing domething stupid! Please help, thanks!


UPDATE thanks to all who responded, I misunderstood the different contexts of whether I was working in an attribute or outside. Sorted my problem out nicely!

If I could I would accept two answers, the one I have, and @Aaron Digulla's, which explained the attributes thing.

Answer

Wayne picture Wayne · Dec 14, 2011

There are two questions here that seem the same, but which are subtly different: 1) How do I reference a variable by name? 2) Where can I reference a variable by name?

First, variables are always referenced using the $varname syntax. Second, this can be done anywhere an expression is allowed. It's the second part of this that seems to confuse. To start with, the value of an element or attribute will by default be output literally, so no variables are actually referenced in the following example:

<element attr="$test">$test or {$test}</element>

The output will literally match what was typed.

To output a variable's value, we need to reference it where an expression is allowed. In element content, we use xsl:value-of; in attributes that are treated as an Attribute Value Template (e.g. the attributes of a literal result element), expressions are delimited by curly braces {}. Assume the following declaration:

<xsl:variable name="test" select="'value'"/>

...then the following:

<element attr="{$test}"><xsl:value-of select="$test"/></element>

...results in:

<element attr="value">value</element>

A few parting notes on AVTs and value-of:

  • In both cases the variable was referenced as $test. The braces in an AVT are not part of the variable reference; they are expression delimiters.
  • In either case, the expression need not have contained a reference to a variable; any XPath expression would have been allowed.
  • Not all attributes in an XSLT document are treated as attribute value templates. For example, notice that xsl:value's select attribute already accepts an expression as content.
  • Question: Why can't you use value-of in an attribute, like this?

    <element attr="<xsl:value-of select="$test"/>"/>
    

    Answer: Because XSLT documents must contain well-formed XML (and that isn't).

  • Question: Why can't you use {$varname} in element content?

    Glib answer: because XSLT's creators didn't design it that way.