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"

¿Fue útil?

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
scroll top