如何使用 Nokogiri 删除节点

How to remove a node using Nokogiri

我有一个这样的 HTML 结构:

<div>
  This is
  <p> very
    <script>
      some code
    </script>
  </p>
   important.
</div>

我知道如何从中获得 Nokogiri::XML::NodeSet

dom.xpath("//div")

我现在想过滤掉任何 script 标签:

dom.xpath("//script")

所以我可以得到类似的东西:

<div>
  This is
  <p> very</p>
   important.
</div>

这样我就可以调用 div.text 得到:

"This is very important."

我尝试 recursively/iteratively 遍历所有子节点并尝试匹配我想要过滤掉任何我不想要的任何节点的每个节点,但我 运行 遇到了太多空格或没有足够的空格。我很确定有一个足够好的和 ruby​​esque 的方式。

执行此操作的好方法是什么?

第一个问题

删除所有脚本节点:

require 'nokogiri'

html = "<div>
  This is
  <p> very
    <script>
      some code
    </script>
  </p>
   important.
</div>"

doc = Nokogiri::HTML(html)

doc.xpath("//script").remove

p doc.text
#=> "\n  This is\n   very\n    \n  \n   important.\n"

感谢@theTinMan 的提示(在一个 NodeSet 而不是每个节点上调用 remove)。

第二题

要删除不需要的空格,您可以使用:

  • strip 删除字符串开头和结尾的空格(空格、制表符、换行符...)
  • gsub 仅用一个空格替换多个空格


p doc.text.strip.gsub(/[[:space:]]+/,' ')
#=> "This is very important."

NodeSet 包含 remove 方法,可以轻松删除与您的选择器匹配的内容:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<html>
  <body>
    <div><p>foo</p><p>bar</p></div>
  </body>
</html>
EOT

doc.search('p').remove
puts doc.to_html

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

应用于您的示例输入:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<div>
  This is
  <p> very
    <script>
      some code
    </script>
  </p>
  important.
</div>
EOT

doc.search('script').remove
puts doc.to_html

# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html><body>
# >> <div>
# >>   This is
# >>   <p> very
# >>     
# >>   </p>
# >>    important.
# >> </div>
# >> </body></html>

那时 <div> 中的文本是:

doc.at('div').text # => "\n  This is\n   very\n    \n  \n   important.\n"

规范化很容易:

doc.at('div').text.gsub(/[\n ]+/,' ').strip # => "This is very important."