Nokogiri相当于jQuery nearest()方法,用于在树中查找第一个匹配的祖先

时间:2011-11-03 23:28:38

标签: ruby dom nokogiri closest ancestor

jQuery有一个可爱的,有点错误的名为closest()的方法,它在DOM树中寻找匹配的元素。例如,如果我有这个HTML:

<table src="foo">
  <tr>
    <td>Yay</td>
  </tr>
</table>

假设element设置为<td>,那么我可以像这样计算src的值:

element.closest('table')['src']

如果表元素或其src属性中的任何一个缺失,那将会干净地返回“undefined”。

在Javascriptland中习惯了这个,我很想在Rubyland中找到与Nokogiri相同的东西,但是我能够想出的最接近的是使用ancestors()这个明显不优雅的黑客:

ancestors = element.ancestors('table')
src = ancestors.any? ? first['src'] : nil

需要三元组,因为如果在空数组上调用,则首先返回nil。更好的想法?

3 个答案:

答案 0 :(得分:11)

您可以在空数组上调用first,问题是它会返回nil而您不能说nil['src']而不会感到悲伤。你可以这样做:

src = (element.ancestors('table').first || { })['src']

如果你在Rails中,你可以这样使用try

src = element.ancestors('table').first.try(:fetch, 'src')

如果你做了很多这样的事情,那就把丑陋隐藏在一个方法中:

def closest_attr_from(e, selector, attr)
  a = e.closest(selector)
  a ? a[attr] : nil
end

然后

src = closest_attr_from(element, 'table', 'src')

您也可以将其修补到Nokogiri :: XML :: Node(但我不推荐它):

class Nokogiri::XML::Node
  def closest(selector)
    ancestors(selector).first
  end
  def closest_attr(selector, attr)
    a = closest(selector)
    a ? a[attr] : nil
  end
end

答案 1 :(得分:6)

您也可以使用xpath执行此操作:

element.xpath('./ancestor::table[1]')

答案 2 :(得分:3)

您想要最近的表祖先的src属性(如果存在)?而不是通过XPath获得可能存在的元素,然后可能通过Ruby获取属性,而不是直接在XPath中请求该属性:

./ancestor::table[1]/@src

您将获得属性或nil:

irb(main):001:0> require 'nokogiri'
#=> true

irb(main):002:0> xml = '<r><a/><table src="foo"><tr><td /></tr></table></r>'
#=> "<r><a/><table src=\"foo\"><tr><td /></tr></table></r>"

irb(main):003:0> doc = Nokogiri.XML(xml)
#=> #<Nokogiri::XML::Document:0x195f66c name="document" children=…

irb(main):004:0> doc.at('td').at_xpath( './ancestor::table[1]/@src' )
#=> #<Nokogiri::XML::Attr:0x195f1bc name="src" value="foo">

irb(main):005:0> doc.at('a').at_xpath( './ancestor::table[1]/@src' )
#=> nil