【问题标题】:Add a class to an element with Nokogiri使用 Nokogiri 向元素添加类
【发布时间】:2011-06-17 23:52:02
【问题描述】:

显然 Nokogiri 的 add_class 方法仅适用于 NodeLists,导致此代码无效:

doc.search('a').each do |anchor|
  anchor.inner_text = "hello!"
  anchor.add_class("whatever") # WHOOPS!
end

我该怎么做才能使这段代码正常工作?我想应该是这样的

doc.search('a').each do |anchor|
  anchor.inner_text = "hello!"
  Nokogiri::XML::NodeSet.new(anchor).add_class("whatever")
end

但这也不起作用。请告诉我,我不必为单个节点实现自己的add_class

【问题讨论】:

    标签: ruby nokogiri


    【解决方案1】:

    旧线程,但它是 Google 的热门话题。您现在可以使用 append_class method 来执行此操作,而不必使用空格分隔符:

    doc.search('a').each do |anchor|
      anchor.inner_text = "hello!"
      anchor.append_class('whatever')
    end
    

    【讨论】:

      【解决方案2】:

      Nokogiri 的add_class,像您发现的那样在 NodeSet 上工作。尝试在 each 块中添加类是行不通的,因为此时您正在处理单个节点。

      改为:

      require 'nokogiri'
      
      html = '<p>one</p><p>two</p>'
      doc = Nokogiri::HTML(html)
      
      doc.search('p').tap{ |ns| ns.add_class('boo') }.each do |n|
        puts n.text
      end
      puts doc.to_html
      

      哪些输出:

      # >> one
      # >> two
      # >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
      # >> <html><body>
      # >> <p class="boo">one</p>
      # >> <p class="boo">two</p>
      # >> </body></html>
      

      在 Ruby 1.9+ 中实现的 tap 方法可以访问节点列表本身,从而允许 add_class 方法将“boo”类添加到 &lt;p&gt; 标记中。

      【讨论】:

      • 你为什么不能做doc.search('p').add_class('boo').each do ...
      • 如果你不想让 Nokogiri 添加 doctype 和其他 html 和 body 标签,你可以使用doc = Nokogiri::HTML.fragment(html)
      【解决方案3】:

      CSS 类只是元素上的另一个属性:

      doc.search('a').each do |anchor|
        anchor.inner_text = "hello!"
        anchor['class']="whatever"
      end
      

      由于 CSS 类在属性中以空格分隔,如果您不确定一个或多个类是否已经存在,您将需要类似

      anchor['class'] ||= ""
      anchor['class'] = anchor['class'] << " whatever"
      

      您需要使用= 显式设置属性,而不是仅仅改变为属性返回的字符串。例如,这不会改变 DOM:

      anchor['class'] ||= ""
      anchor['class'] << " whatever"
      

      即使这会导致完成更多工作,我也可能会这样做:

      class Nokogiri::XML::Node
        def add_css_class( *classes )
          existing = (self['class'] || "").split(/\s+/)
          self['class'] = existing.concat(classes).uniq.join(" ")
        end
      end
      

      如果您不想对课程进行猴子补丁,您也可以:

      module ClassMutator
        def add_css_class( *classes )
          existing = (self['class'] || "").split(/\s+/)
          self['class'] = existing.concat(classes).uniq.join(" ")
        end
      end
      
      anchor.extend ClassMutator
      anchor.add_css_class "whatever"
      

      编辑:您可以看到,这基本上是 Nokogiri 在内部为您通过单击类查看源代码找到的add_class 方法所做的:

      # File lib/nokogiri/xml/node_set.rb, line 136
      def add_class name
        each do |el|
          next unless el.respond_to? :get_attribute
          classes = el.get_attribute('class').to_s.split(" ")
          el.set_attribute('class', classes.push(name).uniq.join(" "))
        end
        self
      end
      

      【讨论】:

      • 扩大ClassMutator!谢谢!
      猜你喜欢
      • 2015-04-03
      • 2023-03-11
      • 2015-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-26
      相关资源
      最近更新 更多