XSLT2: How to reference attributes about the current node in XPath2 predicates

16,219

Solution 1

In XSLT 1.0 you can use the standard function current() which refers to the node that is matched by the current template or the inner-most xsl:for-each:

/potato/stem[@sessionID=current()/@sessionID][scc]/scc/@leafnumber

or by defining a key (at a global level):

<xsl:key name="kPotById" match="stem[scc]" use="@sessionID"/>

and referencing this key:

key('kPotById', @sessionID)/scc/@leafnumber

In XSLT 2.0 / XPath 2.0 you have additional ways to express this (range variables):

for $thisSessionID in @sessionId
 return
    /potato/stem[@sessionID=$thisSessionID][scc]/scc/@leafnumber

Solution 2

Use e.g. current()/@sessionID to access the sessionID attribute of the currently processed node (e.g. the one processed by the for-each in your sample or by an apply-templates with push processing).

Share:
16,219
David R
Author by

David R

Updated on June 04, 2022

Comments

  • David R
    David R about 2 years

    I had posted another question with this as one aspect of it. I was told to clarify the question, but that question was already pretty long and complicated, so I created a new one.

    I want to know if there is standard way of referencing the current node's attribute in an XPath expression testing for another one.

    For an example, consider the following XSLT

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:for-each select="potato/stem[eye]">
            In session <xsl:value-of select="@sessionID"/>, the potato had <xsl:value-of select="/potato/stem[@sessionID=@sessionID][scc]/scc/@leafnumber"/> s.c.c. leaves.
        </xsl:for-each>
    </xsl:template>
    

    (XML source at bottom of this question.) (Note that the for-each references nodes of type stem[eye] but the second value requested references nodes of type stem[scc], which are on a different branch of the source XML tree.)

    Now, obviously, the "@sessionID=@sessoinID" part of that is mostly meaningless because XPath perceives this as "The value of the sessionID attribute of the node should equal ... the value of the sessionID attribute of the node."

    But what I want to say is "Test to make sure the value of the seesionID attribute of that node (the one in the XPath expression) is the same as the sessionID of the node of whatever /stem[eye] node I'm in right now."

    I can't do this with a variable, because you are not allowed to declare a variable within a for-each clause.

    For reference, this is the XML source. Its structure is not what one would like, but it is what I have to work with.

    <?xml version="1.0" encoding="utf-8"?>
    <potato>
    <stem sessionID="1">
        <eye number = "25"/>
    </stem>
    <stem sessionID="3">
        <eye number = "33"/>
    </stem>
    
    <stem sessionID="1">
        <scc leafnumber = "234" />
    </stem>
    <stem sessionID="2">
        <scc leafnumber = "433"/>
    </stem>
    <stem sessionID="3">
        <scc leafnumber = "463"/>
    </stem>
    
    <stem sessionID="1">
        <agd leafnumber = "154"/>
    </stem>
    <stem sessionID="2">
        <agd leafnumber = "233"/>
    </stem>
    <stem sessionID="3">
        <agd leafnumber = "113"/>
    </stem> 
    </potato>
    

    The output I'm looking for is:

    In session 1, the potato had 234 s.c.c. leaves.

    In session 3, the potato had 463 s.c.c. leaves.

    (Of course, this is all just sandbox example. I realize there are probably easy ways to accomplish the above output in a completely different manner, but I hope this example gets across my question, which is how to use values associated with the current node (say, in a for-each) in a predicate for an XPath searching out a different one.)

  • David R
    David R over 12 years
    THANKS! that was exactly what I was trying to figure out. Why on earth did my XSLT book never mention this function?? [XML for Dummies spends 130+ pages on XSLT and never mentions this function.]
  • David R
    David R over 12 years
    Wow, I didn't know about "key" either. Shessh! What a crappy book I have. I will need to look into range variables more as well. This is very helpful.
  • Dimitre Novatchev
    Dimitre Novatchev over 12 years
    @DavidR: You are welcome. BTW, I corrected a typo in my answer -- had missed the 2nd argument in the key() example. Now it is OK.