7

jQuery 有一个可爱的方法,虽然名字有些不妥,叫做close(),它沿着 DOM 树向上寻找匹配的元素。例如,如果我有这个 HTML:

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

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

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

如果 table 元素或其 src 属性中的任何一个丢失,那将干净地返回“未定义”。

在 Javascriptland 中已经习惯了这一点,我很想在 Rubyland 中找到与 Nokogiri 等价的东西,但我能想到的最接近的是使用祖先()的这种明显不雅的 hack :

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

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

4

3 回答 3

12

你可以调用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
于 2011-11-04T00:28:26.803 回答
6

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

element.xpath('./ancestor::table[1]')
于 2011-11-04T00:40:39.773 回答
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
于 2011-11-04T15:56:05.360 回答