GSerg
GSerg

Reputation: 78200

XPath: Query an attribute from a nodeset in a variable

Within an XSL sheet, I have a nodeset in a variable, $context.

How do I properly query an attribute of the topmost node in $context? Obviously, if $context was the current node, I would just write "@attname", but it is not. Currently I do $context/../@attname which is doesn't look great to me.

EDIT

Ok, the data. Here is what I see in the VS.

In case you wonder how I got this strange thing: I UNION'ed a node with it's subnodes and an attribute selected out from a different node:

<xsl:with-param name="context" select=". | ../@res" />.

I'm not completely aware what results from this, but I can see that it works. Highlighted is the attribute I'm interested in.

Maybe that creates an attribute attached to nothing, if that makes sence at all :|

Upvotes: 0

Views: 2061

Answers (3)

Martin Honnen
Martin Honnen

Reputation: 167716

As you have <xsl:with-param name="context" select=". | ../@res" /> the 'res' attribute is part of the node-set (XPath 1.0) or sequence (XPath 2.0) the variable named 'context' is bound to. With XPath 2.0 you could use $context/self::attribute(res) but XPath 1.0 has no comparable expression so what you have already ($context[1] or $context/../@res) is all you can do in my view.

Upvotes: 0

Tomalak
Tomalak

Reputation: 338396

$context/../@attname

does not make too much sense. You can't go "up" here, as this would bring you "outside of" $context.

If the node-set contains something like this (a single node)

<node attname="foo">
  <bar />
</node>

then:

$context/@attname

If it is like this (a list of nodes):

<node attname="foo">
  <bar />
</node>
<node attname="foo">
  <bar />
</node>

then:

$context[1]/@attname

All of this does not work if the variable contains a result tree fragment (RTF). In this case, you need to employ an extension function called node-set(). Most XSLT processors provide this function.


EDIT: Your variable holds a union of the current node and a naked attribute node from its parent:

<xsl:with-param name="context" select=". | ../@res" />

The result of a union will always be in document order, so even though you selected the attribute after the context node in the XPath, in the resulting node set it will come before - the parent of the context node is before the context node in document order.

You need $context[1] to grab the attribute node, and $context[2] to grab the other node.

I must say that this is some strange and probably unnecessary complicated use of variables. I'm sure there is a way to do this in a less painful fashion. For example you could do

 <xsl:with-param name="context" select="." />

and then use $context/../@res in the called template. That would be a lot more straight-forward than what you are trying now.

Also, if the <xsl:with-param> you show here is part of an <xsl:call-template>, you can drop that param entirely. When a template is called (instead of applied), then the context node does not change, passing it in is redundant.

Upvotes: 1

Martijn Laarman
Martijn Laarman

Reputation: 13536

In addition to tomalak's answer if you ever do need to propagate back up to the root you could try:

ancestor::*[not(..)]

Would love to hear of a situation where you might want/need this though.

Try it yourself by pasting:

//pet/ancestor::*[not(..)]

in this online Xpath test tool.

Upvotes: 0

Related Questions