XSL: how to check if the current node is a descendant of another node

I am new to XSLT, but I need to use it for use in CMS. I already had a problem, but I will try to describe it without going into too much information about the underlying CMS. If you need more context to help me, I can add it.

So, all I want to do is check if the node of my xml is a descendant of a specific node.

<xsl:if test="$currentNode::IsADescendantOf($someNode)"> Write this out. </xsl:if> 

Any ideas anybody?

Thanks in advance:)

+4
source share
5 answers

You should use the union operation and node -set size:

 <xsl:if test="count($someNode|$currentNode/ancestor::*) = count($currentNode/ancestor::*)"> Write this out. </xsl:if> 

If $ someNode is an ancestor of $ currentNode, $ someNode | $ currentNode / ancestor :: * will return the same node -set since $ currentNode / ancestor :: * (node-set does not have any doubling).

If not, the first node -set will have another node than the second due to merging.

+5
source

The portable (XPath 1.0 and 2.0) solution would be:

 <xsl:if test=" $currentNode/ancestor::*[generate-id() = generate-id($someNode)] "> Write this out. </xsl:if> 

This raises the axis of the ancestor and checks each element in it. If (and only if) the unique identifier of one of the ancestors corresponds to the unique identifier $someNode , then the resulting node -set is not empty.

Non-empty node-sets evaluate to true, so the condition is met.

Test - find all <baz> that are descendants of <foo> :

 <xml> <foo> <bar> <baz>Test 1</baz> </bar> </foo> <baz>Test 2</baz> </xml> 

and

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:template match="/"> <xsl:variable name="someNode" select="//foo[1]" /> <!-- test each <baz> node if it has <foo> as a parent --> <xsl:for-each select="//baz"> <xsl:if test=" ancestor::*[generate-id() = generate-id($someNode)] "> <xsl:copy-of select="." /> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

leads to

 <baz>Test 1</baz> 

Note that if you are referring to the current current node, as I do in for-each, there is no need for a separate $currentNode variable. All XPath defaults to the current node.

The option will be from top to bottom. It is less effective, though (probably several orders of magnitude):

 <xsl:if test=" $someNode[//*[generate-id() = generate-id($currentNode)]] "> Write this out. </xsl:if> 
+2
source

Look at the ancestor axis in your XSL / XPath link

 <xsl:if test="ancestor::*[. is $somenode]"> 

EDIT: I'm studying with you. See if this works (I want my XSL debugger to be available on this system :-)

+1
source

The answer is pretty simple

all you have to do is:

 <xsl:if test="count(ancestor::somenode)>0"> 

... then add the rest

the logic is that if a node is a descendant of somenode, then it will have one or more of this node.

+1
source

Child Testing

The best way is to use the descendant axis :: *.

If you have an XML fragment similar to this and you want to combine descendant nodes <a> with the first <alpha> node.

XML

 <root> <!-- check for descendants of the following alpha node--> <alpha> <!-- match the following node--> <a>...</a> <b>...</b> <c>...</c> </alpha> <alpha> <a>...</a> <c>...</c> </alpha> </root> 

XSLT

 <xsl:if test="/root/alpha[1]/descendant::a[. is current()]"> 

Ancestor Check

This will probably work in most cases.

 <xsl:if test="ancestor::*[name() = $node]"> 

Where

 <xsl:variable name="node" select="name(//alpha)"/> 

Or you can just use generate-id () if you have multiple nodes to compare and you need to make sure that it is a node match, not a name match.

 <xsl:variable name="node" select="generate-id(//alpha[3])"/> <xsl:if test="ancestor::*[generate-id(.) = $node]"> 

The comparison operator is cannot use IMO when comparing ancestors, since it requires a leaf node and leaf nodes have no children.

But I would recommend using the axis of the descendant :: *, since it was more readable and flexible.

0
source

All Articles