Re: [xsl] Possible MSXML 3 / 4 bug: using a for-each on xsl:variable / tre e-frag is misbehaving

Subject: Re: [xsl] Possible MSXML 3 / 4 bug: using a for-each on xsl:variable / tre e-frag is misbehaving
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Tue, 14 May 2002 15:00:25 +0100
Hi Jeff,

> Here's what I'm seeing: Within an xsl:for-each element, where the
> select is made against an xsl:variable tree-frag, xpath statements
> are failing to nodes outside of the given for-each's context.

I think you're seeing correct behaviour here. Within the xsl:for-each:

>          <xsl:for-each select="msxsl:node-set($items)/item">
>             <using_msxsl_node-set child-id="{@id}">
>                <xsl:copy-of select="/xml/an-element"/>
>             </using_msxsl_node-set>
>          </xsl:for-each>

the current node is an item element within the node set derived from
the $items node set. The path /xml/an-element is resolved relative to
the current node -- the / means the root node of the node tree in
which the item resides.

The $items result tree fragment is generated with:

>          <xsl:variable name="items" >
>             <xsl:copy-of select="//item"/>
>          </xsl:variable>

which means that the result tree fragment is a root node with a number
of item elements as children. The result tree fragment doesn't contain
any xml elements or an-element elements, so it shouldn't surprise you
that it doesn't return anything.

I think that perhaps you're expecting that / always gives you the root
node of the source of the transformation? That's not the case -- it
gives you the root node of the node tree of which the context node is
a part.

So to achieve what you want, store the root node of the source of the
transformation in a (global) variable:

<xsl:variable name="source" select="/" />

and then use that as the basis of your path within the xsl:for-each:

  <xsl:for-each select="msxsl:node-set($items)/item">
    <using_msxsl_node-set child-id="{@id}">
      <xsl:copy-of select="$source/xml/an-element"/>
    </using_msxsl_node-set>
  </xsl:for-each>

---
  
In XPath 2.0, there's a new function called input() that returns the
node(s) that invoked the transformation. So in XSLT 2.0, you could do:

  <xsl:variable name="items">
    <xsl:copy-of select="//item" />
  </xsl:variable>
  <xsl:for-each select="$items/item">
    <using_temporary_tree child-id="{@id}">
      <xsl:copy-of select="input()/xml/an-element" />
    </using_temporary_tree>
  </xsl:for-each>
  
Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread