...">

Get all the ancestors of the current node

I want to get all the ancestors of the current node:

ls5co.gif

XML:

<root> <item title="a"> <item title="b"> <item title="c"></item> <!--CURRENT--> <item title="d"></item> </item> <item title="x"> <item title="y"></item> <item title="z"></item> </item> </item> </root> 

Result:

 <item title="a">...</item> <item title="b">...</item> 

Edit: Answers with ax ancestors are in order. My problem was elsewhere in XSLT

XSLT:

 <xsl:variable name="curr" select="//item[@title = 'c']"></xsl:variable> <xsl:variable name="test" select="$curr/ancestor::item"></xsl:variable> <xsl:for-each select="$test/item"> <xsl:value-of select="@title"></xsl:value-of> </xsl:for-each> 

Return:

 bcdx 

Edit2: for dimitre and for everyone who has a similar problem

All the answers to my question were good.

Just XSLT (up) returns me a weird result, and @Mads Hansen corrected me.

FINAL WORKING EXAMPLE:

XML:

 <?xml version="1.0" encoding="utf-8"?> <root> <item title="a"> <item title="b"> <item title="c"></item> <item title="d"></item> </item> <item title="x"> <item title="y"></item> <item title="z"></item> </item> </item> </root> 

XSLT:

 <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <xsl:variable name="curr" select="//item[@title = 'c']"></xsl:variable> <xsl:variable name="test" select="$curr/ancestor::item"></xsl:variable> <xsl:for-each select="$test"> <xsl:value-of select="@title"></xsl:value-of> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

Return:

 ab 
+4
source share
4 answers

Check with Adam for a very quick first answer.

Just add some details:

Your expected result does not match your words. the root element is also the ancestor of the node, and the document is also the ancestor of the node.

 ancestor::node() 

... will return the sequence in the following order:

  • item[@title='b']
  • item[@title='a']
  • root element (aka document element)
  • root node /

To get the specific result that you specified, you need:

 ancestor::item/. 

Effect/. consists in changing the order of the document forward order. Native ancestor order :: - reverse document order.


Update: Illustration of dots made in the comments feed.

This style sheet (with OP input) ...

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:for-each select="//item[@title='c']"> <xsl:value-of select="ancestor::item[1]/@title" /> <xsl:value-of select="ancestor::item[2]/@title" /> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

... displays "ba" illustrating the point at which the ancestor :: is indeed the inverse axis. And yet this style sheet ...

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:for-each select="//item[@title='c']"> <xsl:value-of select="(ancestor::item/@title)[1]" /> <xsl:value-of select="(ancestor::item/@title)[2]" /> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

... has the opposite result "ab". This is instructive because it shows that in XSLT 1.0 (not so in XSLT 2.0), the brackets remove the inverse and become documented node-set.

The OP asked about the conversion of something like ....

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:for-each select="//item[@title='c']"> <xsl:for-each select="ancestor::item"> <xsl:value-of select="@title" /> </xsl:for-each> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

This returns ab (in XSLT 2.0 it returns "ba"). What for? Because in XSLT 1.0, the xsl: for-each command ignores the back axis of the axis and processes in document order (unless the xsl: sort instruction is specified otherwise).

+5
source

I want to get all the ancestors of the current node

Assigned nodes are obviously not all the ancestors of a green node.

To select all ancestors, use :

 ancestor::node() 

This selects all the ancestral nodes of the original node (or current node) connection, including the top element and its parent element - root node / - which is node but not element.

To select all ancestors of elements, use :

 ancestor::* 

This is similar to the previous expression, but does not select the root node ( / ) because it isn’t an element.

To select all ancestors named item , use :

 ancestor::item 

Do note . All the expressions above assume that (//item[@title='c'])[1] is the initial context of the node (current node). If this assumption is incorrect, then (//item[@title='c'])[1]/ should be added to each of the expressions.

Note 2 . I highly recommend using a tool like XPath Visualizer to learn XPath. Over the years, this tool has helped many thousands of people learn XPath in an interesting way - by playing with XPath expressions and observing their evaluation results.

Note Visualizer XPath was created by me in 2000 and has never been a financial product. I recommend this based solely on its value to users verified over many years.

+3
source

You can use xpath ancestor::item

+2
source

The reason you output bcdx instead of ab is because your <xsl:for-each> iterates over all the item child elements of the selected item elements, rather than just iterating over the selected elements in the $test variable.

Change for each to simply iterate over $test :

 <xsl:variable name="curr" select="//item[@title = 'c']"></xsl:variable> <xsl:variable name="test" select="$curr/ancestor::item"></xsl:variable> <xsl:for-each select="$test"> <xsl:value-of select="@title"></xsl:value-of> </xsl:for-each> 
+1
source

Source: https://habr.com/ru/post/1433574/


All Articles