encontrar ancestro común de un grupo de XPath?
Pregunta
decir que tengo
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
¿Cómo puedo obtener el antepasado común? en este caso lapso sería el ancestro común de "font, h1, b, div" sería "span"
Solución
Para encontrar un ancestro común entre dos nodos:
(node1.ancestors & node2.ancestors).first
Una función más general que trabaja con múltiples nodos:
# 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>
Otros consejos
La función common_ancestor
a continuación hace lo que quiere.
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>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow