Sivabalakrishnan
Sivabalakrishnan

Reputation: 515

Passing local variable from one template to another in xslt

I need to pass value of the local variable defined in one template to another template.

The following source does not work (ie I cant able to pass local variable to another template ) . What's wrong ? Thanks a lot in advance.

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

      <xsl:template match="/">
        <xsl:apply-templates select="A/B/C">
        </xsl:apply-templates>
        <xsl:apply-templates select="A/B/D/E/F">
          <xsl:with-param name="XYZ" select="$XYZ" >
          </xsl:with-param>
        </xsl:apply-templates>
      </xsl:template>

      <xsl:template match="A/B/C">
        <xsl:variable name="XYZ">
          <xsl:value-of select="K/L/M/N/O"/>
        </xsl:variable>
      </xsl:template>

      <xsl:template match="A/B/D/E/F">
        <xsl:text>BLAH-BLAH-BLAH-111</xsl:text>
        <xsl:value-of select="$XYZ" />
        <xsl:text>BLAH-BLAH-BLAH-999</xsl:text>
      </xsl:template>
    </xsl:stylesheet>`

Upvotes: 1

Views: 2513

Answers (2)

Michael Kay
Michael Kay

Reputation: 163595

What your non-working code appears to do is:

  • A calls B
  • B sets a local variable $XYZ
  • A calls C
  • You would like C to have access to $XYZ

The problem isn't passing a parameter from A to C: that's easy. The problem is returning the value of $XYZ from B to its caller A.

The way of doing this depends on which version of XSLT you are using.

  • In XSLT 1.0, the only thing you can return from a template is a chunk of XML. Template B needs to wrap up everything it wants to return in an XML fragment, template A needs to capture that XML fragment in a variable. To be useful it then needs the exslt:node-set() extension to turn the XML fragment into a node-set, from which it can extract the parts that it needs.

  • In XSLT 2.0, an additional option is to return a sequence of things (e.g. XML nodes) from a template: the caller could then, for example, copy the first item in that sequence to the transformation result, and pass the second item in the sequence to another template for further processing.

  • In XSLT 3.0, you could use a map instead of a sequence, so the different things in the result are identified by name rather than by position.

All of this is very dry and academic. We could give you a much better answer if you actually told us what your transformation is trying to do (what is the input, what is the output, and how are they related?). Perhaps all this stuff about passing parameters means you are going about the job the wrong way and you'd be better off with a completely different approach.

Upvotes: 2

Tim C
Tim C

Reputation: 70648

You need to declare the parameter, with xsl:param in the matching template

<xsl:template match="A/B/D/E/F">
    <xsl:param name="XYZ" />
    <xsl:text>BLAH-BLAH-BLAH-111</xsl:text>
    <xsl:value-of select="$XYZ" />
    <xsl:text>BLAH-BLAH-BLAH-999</xsl:text>
  </xsl:template>

However, there is a problem with your block of code that selects this template

 <xsl:apply-templates select="A/B/D/E/F">
    <xsl:with-param name="XYZ" select="$XYZ" >
 </xsl:with-param>

The xsl:with-param is selecting a variable name XYZ to pass as the parameter, but this variable does not exist in the template. Perhaps you expect it to use the variable defined in the template matching "A/B/C"? This won't happen because variables are local in scope to the block in which they are declared.

Perhaps you need to write your XSLT like so:

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

  <xsl:template match="/">
    <xsl:variable name="XYZ">
      <xsl:apply-templates select="A/B/C" />
    </xsl:variable>
    <xsl:apply-templates select="A/B/D/E/F">
      <xsl:with-param name="XYZ" select="$XYZ" />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="A/B/C">
      <xsl:value-of select="K/L/M/N/O"/>
  </xsl:template>

  <xsl:template match="A/B/D/E/F">
    <xsl:param name="XYZ" />
    <xsl:text>BLAH-BLAH-BLAH-111</xsl:text>
    <xsl:value-of select="$XYZ" />
    <xsl:text>BLAH-BLAH-BLAH-999</xsl:text>
  </xsl:template>
</xsl:stylesheet>

When you apply it to this XML

<A>
  <B>
    <C>
      <K>
        <L>
          <M>
            <N>
              <O> *** Parameter *** </O>
            </N>
          </M>
        </L>
      </K>
    </C>
    <D>
      <E>
        <F>Test</F>
      </E>
    </D>
  </B>
</A>

The following is output

BLAH-BLAH-BLAH-111 *** Parameter *** BLAH-BLAH-BLAH-999

Upvotes: 3

Related Questions