Find a common parent using Xpath

I was wondering if there is a way to access the shared parent node using Xpath.

<outer> <main> <a><b> sometext </b></a> <c><d> sometext2 </d></c> </main> </outer> 

I have text nodes sometext and sometext2. Is there a way that I can access the main (common parent) of these two nodes? I do not know the xml layout containing these nodes.

Any help is appreciated.

Thanks RP

+3
source share
2 answers

Use the following XPath 1.0 expression :

 $v1/ancestor::* [count(. | $v2/ancestor::*) = count($v2/ancestor::*) ] [1] 

, where $ v1 and $ v2 contain two text nodes (if you are not using XPath in XSLT, you will have to replace $ v1 and $ v2 in the above expression with XPath expressions that select each of these two text nodes).

Explanation

The above XPath 1.0 expression finds the intersection of two node-sets : node -set of all the ancestors of the element $ v1 and node -set of all the ancestors of the elements of $ v2. This is done using the so-called Kaysian method for crossing (after Michael Kay, who discovered this in 2000). Using the Kaysian method to intersect, the intersection of two nodes, $ ns1 and $ ns2, is selected with the following XPath expression :

  $ns1[count(. | $ns2) = count($ns2)] 

Then from the intersection of the ancestors, we must select the last element . However , because we use the back axis (ancestor), the required node position must be indicated as 1 .

You can quickly verify that the above XPath expression actually selects the smallest common ancestor using the following transformation:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="v1" select="/*/*/a/b/text()"/> <xsl:variable name="v2" select="/*/*/c/d/text()"/> <xsl:variable name="vCommonAncestor" select= "$v1/ancestor::* [count(. | $v2/ancestor::*) = count($v2/ancestor::*) ] [1]" /> <xsl:template match="/"> <xsl:value-of select="name($vCommonAncestor)"/> </xsl:template> </xsl:stylesheet> 

when applied to the originally provided XML document (fixed for correct XML):

 <outer> <main> <a> <b>sometext</b> </a> <c> <d>sometext2</d> </c> </main> </outer> 

the desired result (the name of the element that is the smallest common ancestor of two text nodes) is created :

Main

An XPath 2.0 expression that selects the lowest common ancestor of two nodes is simpler because it uses the standard XPath 2.0 "intersect" statement:

  ($v1/ancestor::* intersect $v2/ancestor::*) [last()] 
+14
source

It seems complicated. Just try:

 xquery version "3.0"; let $test := <outer> <main> <a><b> sometext </b></a> <c><d> sometext2 </d></c> </main> </outer> return ($test//*[.//b][.//d])[last()] 

to get, i.e. the closest common ancestor

0
source

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


All Articles