XSL: How best to store a node in a variable and then use it in future xpath expressions?

58,680

Solution 1

Try this example:

<xsl:variable name="hotels" select="/results/hotels[active='true']" />
<xsl:variable name="three_star_or_less"
              select="$hotels[number(rating) &lt;= 3]" />
<xsl:for-each select="$three_star_or_less">
    <xsl:sort select="rating" />
    <xsl:value-of select="rating" />
</xsl:for-each>

Solution 2

There is no problem storing a node-set in a variable in XSLT 1.0, and no extensions are needed. If you just use an XPath expression in select attribute of xsl:variable, you'll end up doing just that.

The problem is only when you want to store the nodes that you yourself had generated in a variable, and even then only if you want to query over them later. The problem here is that nodes you output don't have type "node-set" - instead, they're what is called a "result tree fragment". You can store that to a variable, and you can use that variable to insert the fragment into output (or another variable) later on, but you cannot use XPath to query over it. That's when you need either EXSLT node-set() function (which converts a result tree fragment to a node-set), or XSLT 2.0 (in which there are no result tree fragments, only sequences of nodes, regardless of where they come from).

For your example as given, this doesn't seem to be a problem. Rubens' answer gives the exact syntax.

Solution 3

Another note, if you want to be able to use the variable as part of an XPath statement, you need to select into the variable with <xsl:copy-of select="."/> instead of <xsl:value-of select="."/>

value-of will only take the text of the node and you wont be able to use the node-set function to return anything meaningful.

<xsl:variable name="myStringVar">
   <xsl:value-of select="."/>
</xsl:variable>

<!-- This won't work: -->
<Output>
   <xsl:value-of select="node-set($myStringVar)/SubNode" />
</Output>


<xsl:variable name="myNodeSetVar">
   <xsl:copy-of select="."/>
</xsl:variable>

<!-- This will work: -->
<Output>
   <xsl:value-of select="node-set($myNodeSetVar)/SubNode" />
</Output>
Share:
58,680
Pete Duncanson
Author by

Pete Duncanson

Updated on July 09, 2022

Comments

  • Pete Duncanson
    Pete Duncanson almost 2 years

    I need to be able to store a node set in variable and then perform more filting/sorting on it afterward. All the examples I've seen of this involve either using XSL2 or extensions neither of which are really an option.

    I've a list of hotels in my XML doc that can be sorted/filtered and then paged through 5 at a time. I'm finding though I'm repeating alot of the logic as currently I've not found a good way to store node-sets in xsl variable and then use xpath on them for further filtering/sorting.

    This is the sort of thing I'm after (excuse the code written of the top of my head so might not be 100%):

    <xsl:variable name="hotels" select="/results/hotels[active='true']" />
    <xsl:variable name="3_star_or_less" select="/results/hotels[number(rating) <= 3]" />
    <xsl:for-each select="3_star_or_less">
      <xsl:sort select="rating" />
    </xsl:for-each>
    

    Has anyone got an example of how best to do this sort of thing?

  • Pete Duncanson
    Pete Duncanson over 14 years
    EXSLT looks like a possibility. I'll have a play around with that, I like the look of just including the node-set functionality on its own: exslt.org/howto.html#templates
  • PeerBr
    PeerBr over 10 years
    Other than that (couldn't edit my comment), thanks for the helpful post. '<xsl:copy-of>' was just what I was looking for!
  • vinc17
    vinc17 over 3 years
    You're not answering the original question (where extensions are excluded) since the node-set() function is not standard.