Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.)

like image 431
David R Avatar asked Oct 28 '11 08:10

David R


People also ask

What is a current node in XPath How can it be accessed?

The current node is the node in the source XML document best matched by an XSLT template. The current node becomes the starting context node for each XPath expression in the matched template. The current node can be accessed as current() within XPath predicates.

What does node () mean in XSLT?

1. Well, more precisely, node() means child::node(), and @* means attribute::*, so it is matching all children and attributes of the context node. (It doesn't match document nodes or namespace nodes).

What is current in XSLT?

XSLT current() Function The current() function returns a node-set that contains only the current node. Usually the current node and the context node are the same.


2 Answers

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
like image 145
Dimitre Novatchev Avatar answered Oct 16 '22 05:10

Dimitre Novatchev


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).

like image 39
Martin Honnen Avatar answered Oct 16 '22 05:10

Martin Honnen