【问题标题】:Nokogiri equivalent of jQuery closest() method for finding first matching ancestor in treeNokogiri 等效于 jQuery 最接近()方法,用于在树中查找第一个匹配的祖先
【发布时间】:2011-12-21 15:20:04
【问题描述】:

jQuery 有一个名为closest() 的可爱的方法,虽然名字有点错误,但它会沿着 DOM 树向上寻找匹配的元素。例如,如果我有这个 HTML:

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

假设element 设置为&lt;td&gt;,那么我可以像这样计算src 的值:

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

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

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

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

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

【问题讨论】:

    标签: ruby dom nokogiri closest ancestor


    【解决方案1】:

    您想要最近的表祖先的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
    

    【讨论】:

      【解决方案2】:

      你也可以用 xpath 做到这一点:

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

      【讨论】:

        【解决方案3】:

        你可以在一个空数组上调用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
        

        【讨论】:

        • 由于详尽无遗而接受了答案——可能只是将您的补丁作为拉取请求提交给 Nokogiri!
        • Ruby 2.3 引入了safe navigation operator&amp;.,所以你可以做到element.ancestors('table').first&amp;.src
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-25
        • 2021-02-08
        相关资源
        最近更新 更多