如何搜索和替换节点Nokogiri?

时间:2013-07-04 21:37:47

标签: ruby nokogiri

我有一个HTML文档作为字符串。我用Nokogiri解析了它:

doc_str = <<-mydoc
  <p>Lorem ipsum dolor sit foo.</p>
  <h2>Consectetur adipisicing bar</h2>
  <p>Foo do <a href="/c-foo.aspx" class = "foo" title="Foo bar.">foofoo foo</a>.</p>
mydoc

doc = Nokogiri::HTML doc_str

我希望在所有可见文字中将"foo" / "Foo"替换为"Bar" / "bar"

desired = <<-mydoc
  <p>Lorem ipsum dolor sit bar.</p>
  <h2>Consectetur adipisicing bar</h2>
  <p>Bar do <a href="/c-foo.aspx" class = "foo" title="Bar bar.">foofoo bar</a>.</p>
mydoc

我该怎么做?

我尝试阅读Nokogiri tutorial,其中描述了Nokogiri::HTML::Document#at_css。使用Ruby 2.0和最新的Nokogiri,doc.at_css 'h1'返回nil,因此h1.content = "something"甚至不可能。

即使它有效,它也只是解决我的发现和替换问题的第一步。

1 个答案:

答案 0 :(得分:3)

doc.at_css 'h1'会返回nil,因为HTML中没有h1个元素。 doc.at_css 'h2'正确返回Nokogiri::XML::Element元素的h2对象。

CSS选择器无法选择文本节点,并且对于这类事物来说是一个糟糕的工具。 XPath将完成CSS所做的一切以及更多。文档根目录下任何位置的文本节点都只是//text()

编辑我刚刚注意到您似乎希望属性的内容以相同的方式发生变化。 @*匹配任何属性,因此XPath表达式变为//@* | //text()。虽然我不清楚这一点,因为href="/c-foo.aspx"class="foo"保持不变,但title="Foo bar."变为title="bar bar."。我相信你可以自己解决这个问题。

您需要使用XPath查找所有文本节点,然后使用content获取每个节点的文本值。根据需要进行修改,并使用content=替换它。

该程序演示。 to_html方法将数据包装在使其成为有效HTML所必需的标记中。

require 'nokogiri'

doc_str = <<-HTML
  <p>Lorem ipsum dolor sit foo.</p>
  <h2>Consectetur adipisicing bar</h2>
  <p>Foo do <a href="/c-foo.aspx" class = "foo" title="Foo bar.">foofoo foo</a>.</p>
HTML

doc = Nokogiri::HTML(doc_str)

doc.xpath('//@*', '//text()').each do |node|
  node.content = node.content.gsub(/\bfoo\b/, 'bar').gsub(/\bFoo\b/, 'Bar')
end

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>
<p>Lorem ipsum dolor sit bar.</p>
  <h2>Consectetur adipisicing bar</h2>
  <p>Bar do <a href="/c-bar.aspx" class="bar" title="Bar bar.">foofoo bar</a>.</p>
</body></html>