Find a common ancestor from the xpath group?

say that I have

html/body/span/div/p/h1/i/font html/body/span/div/div/div/div/table/tr/p/h1 html/body/span/p/h1/b html/body/span/div 

How can I get a common ancestor? in this case the span will be the common ancestor of the font ", h1, b, div" will be "span"

+1
source share
2 answers

To find a common pedigree between two nodes:

 (node1.ancestors & node2.ancestors).first 

A more generalized function that works with multiple nodes:

 # accepts node objects or selector strings class Nokogiri::XML::Element def common_ancestor(*nodes) nodes = nodes.map do |node| String === node ? self.document.at(node) : node end nodes.inject(self.ancestors) do |common, node| common & node.ancestors end.first end end # usage: node1.common_ancestor(node2, '//foo/bar') # => <ancestor node> 
+3
source

The common_ancestor function below does what you want.

 require 'rubygems' require 'nokogiri' doc = Nokogiri::XML(DATA) def common_ancestor *elements return nil if elements.empty? elements.map! do |e| [ e, [e] ] end #prepare array elements.map! do |e| # build array of ancestors for each given element e[1].unshift e[0] while e[0].respond_to?(:parent) and e[0] = e[0].parent e[1] end # merge corresponding ancestors and find the last where all ancestors are the same elements[0].zip(*elements[1..-1]).select { |e| e.uniq.length == 1 }.flatten.last end i = doc.xpath('//*[@id="i"]').first div = doc.xpath('//*[@id="div"]').first h1 = doc.xpath('//*[@id="h1"]').first p common_ancestor i, div, h1 # => gives the p element __END__ <html> <body> <span> <p id="common-ancestor"> <div> <p><h1><i id="i"></i></h1></p> <div id="div"></div> </div> <p> <h1 id="h1"></h1> </p> <div></div> </p> </span> </body> </html> 
0
source

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


All Articles