Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSL: passing variables between templates

Tags:

xml

xslt

Is it possible to pass a variable from one parent template to its child element ?

<xsl:template match="structure">
  <xsl:variable name="var"><xsl:value-of select="@path" /></xsl:variable>
  <xsl:apply-templates select="folders">
    <xsl:with-param name="var1" select="'{var}'"/>
  </xsl:apply-templates>
</xsl:template> 

this template will match:

<xsl:template match="folder">
  <xsl:param name="var1"/>
  <xsl:value-of select="$var1"/>
</xsl:template>

You see I wanna use var as var1 in the matched template.

How can I make this work?

edit: the structure is like this:

<structure path="C:\xampplite\htdocs\xampp">
  <folders>
    <folder name="img">
      <date>01/28/10 21:59:00</date>
      <size>37.4 KB</size>
    </folder>
 </folders>
</structure>

edit2:

<xsl:template match="folder">
<xsl:variable name="var1"><xsl:value-of select="../../@path"/></xsl:variable>
<xsl:variable name="var2"><xsl:value-of select="@name" /></xsl:variable>
<xsl:variable name="var3"><xsl:value-of select="$var1"/>\<xsl:copy-of select="$var2"/>    </xsl:variable>
 <th colspan="2" align="left"  bgcolor="#FF5500"><a onclick="foo('{$var3}')"><xsl:value-of select="$var3"/></a></th>

in the jscript function the string is without its backslashes. anyone knows why?

C:xampplitehtdocsxamppimg

like image 820
binaryguy Avatar asked Jan 30 '10 09:01

binaryguy


People also ask

How do you pass a variable in an xsl template?

You are applying templates selecting folders , but have a template matching on folder . Either change it to folder , or if you have a folders template make sure that it passes the var1 parameter value down to the folder template. Your with-param @select uses '{var}' , which selects that literal string {var} .

What is param in XSLT?

XSLT <xsl:param> The <xsl:param> element is used to declare a local or global parameter. Note: The parameter is global if it's declared as a top-level element, and local if it's declared within a template.

What does xsl apply templates select * /> mean?

The <xsl:apply-templates> element applies a template to the current element or to the current element's child nodes. If we add a "select" attribute to the <xsl:apply-templates> element, it will process only the child elements that matches the value of the attribute.

What is xsl apply templates select () />?

XSLT apply-templates define how to find elements and help in removing unwanted text in the document. It applies a template rule to the current child nodes. It adds a select attribute along with the template to specify the order of child nodes to process the current task with the help of the XSLT processor.


2 Answers

You can pass parameters to named templates that you call via <xsl:call-template>, e.g.:

<xsl:call-template name="name">
   <xsl:with-param name="param" select="xpathexpr"/>
</xsl:call-template>

<xsl:template name="name">
   <xsl:param name="param"/>
   ...
</xsl:template>

When you call a named template, the context node is the current context. So to call a named template for child nodes, you need to change the current context by using <xsl:for-each>:

<xsl:for-each select="child">
   <xsl:call-template name="name">
      <xsl:with-param name="param" select="xpathexpr"/>
   </xsl:call-template>
</xsl:for-each>

In your case, though, there's no need to pass parameters, since the variable that you're trying to use is something that's navigable to from the context node. And you don't need to use all those variables (nor should you ever give a variable a name as useless as var1):

<xsl:template match="folder">
   <xsl:variable name="linkarg" value="concat(../../@path, '\\', @name)"/>
   <xsl:variable name="linktext" value="concat(../../@path, '\', @name)"/>
   <th colspan="2" align="left"  bgcolor="#FF5500">
      <a onclick="foo('{$linkarg}')">
         <xsl:value-of select="$linktext"/>
      </a>
   </th>
</xsl:template>

Also, I'd be tempted to use ancestor::structure[1]/@path rather than ../../@path, because it makes the intention a lot more explicit; your version means "get the path attribute from the parent of the parent element", while my version means "traverse up the chain of ancestor elements until you find the first one named structure, and get its path attribute."

like image 98
Robert Rossney Avatar answered Oct 18 '22 12:10

Robert Rossney


When using XSLT 2.0, it is possible to pass parameters to child templates, by adding tunnel="yes" to the <xsl:with-param .../> at the callsite, and to the </xsl:with-param .../> element at the called template as well. Just do:

<xsl:template match="folder">
  <xsl:param name="var1" tunnel="yes"/> <!-- note the 'tunnel="yes"' attribute here! -->
  <xsl:value-of select="$var1"/>
</xsl:template>

<xsl:template match="structure">
  <xsl:variable name="var"><xsl:value-of select="@path" /></xsl:variable>
  <xsl:apply-templates select="folders">
    <xsl:with-param name="var1" select="$var" tunnel="yes"/> <!-- note the 'tunnel' attribute here, too! -->
  </xsl:apply-templates>
</xsl:template>

For further information, please refer to the section 10.1.2 Tunnel parameters in the XSLT 2.0 specification.


An extended example

With tunnel parameters, you could even do this:

<xsl:template match="structure">
   <!-- same as before -->
</xsl:template>

<xsl:template match="folder">
  <!-- Look, ma, no param declaration! -->
  <!-- ... -->
  <xsl:apply-templates select="date"/>
  <!-- ... -->
</xsl:template>

<xsl:template match="folder/date">
   <xsl:param name="var1" tunnel="yes"/>
   <xsl:value-of select="$var1"/>
</xsl:template>

Because of the tunnel attribute, the var1 parameter is passed from the initial template through all intermediate templates into the "folder/date" template.

Just remember that the tunnel="yes" attribute declaration must be present both on the <xsl:param name="var1" tunnel="yes"/> AND the corresponding <xsl:with-param name="var1" tunnel="yes" select="..."/> attribute.

like image 35
cr7pt0gr4ph7 Avatar answered Oct 18 '22 12:10

cr7pt0gr4ph7