如何更改具有匹配内容的元素的 class

How to change the class of elements that have matching content

我有:

<div class="bar">baz</div>
<div class="foo">qux</div>
<div class="foo">qux</div>
<div class="foo">baz</div>
<div class="foo">qux</div>
<div class="foo">baz</div>
<div class="foo">qux</div>

而且我希望所有包含与 "bar" 的 class 相同内容的元素也具有 "bar" 的 class,就像这样:

<div class="bar">baz</div>
<div class="foo">qux</div>
<div class="foo">qux</div>
<div class="bar">baz</div>
<div class="foo">qux</div>
<div class="bar">baz</div>
<div class="foo">qux</div>

但我不能只搜索 "baz",因为该内容可能会更改。相反,我必须弄清楚单独的 "bar" div 中有什么,然后找到匹配它的其他人并将它们的 class 也更改为 "bar"。

我已经设法将第一个 "bar" 元素的内容放入变量中:

var = body.css(".bar").first.inner_text

但就查找匹配内容和替换 class 而言,我从那里尝试过的任何事情都没有奏效。

您可以使用body.css('div:contains("<text-to-match>")')来匹配包含您想要的文本内容的节点。

您可以通过以下方式实现您想要的效果:

require 'nokogiri'

input = '<div class="bar">baz</div>
<div class="foo">qux</div>
<div class="foo">qux</div>
<div class="foo">baz</div>
<div class="foo">qux</div>
<div class="foo">baz</div>
<div class="foo">qux</div>'

body = Nokogiri::HTML.fragment(input)

text_to_match = body.at_css('.bar').text

matching_nodes = body.css("div:contains('#{text_to_match}')")
matching_nodes.each do |node|
  node['class'] = 'bar'
end

puts body.to_html

小心使用body.css("div:contains('#{text_to_match}')")

input = '<div class="bar">baz</div>
<div class="foo">qux</div>
<div class="foo">qux</div>
<div class="foo">baza</div>
<div class="foo">qux</div>
<div class="foo">bazfdsfsdf</div>
<div class="foo">qux</div>'

输出将是:

<div class="bar">baz</div>
<div class="foo">qux</div>
<div class="foo">qux</div>
<div class="bar">baza</div>
<div class="foo">qux</div>
<div class="bar">bazfdsfsdf</div>
<div class="foo">qux</div>

如果你想在两个元素中匹配完全相同的文本,你应该使用: body.css("div[text() = '#{text_to_match}']")

input = '<div class="bar">baz</div>
<div class="foo">qux</div>
<div class="foo">qux</div>
<div class="foo">baza</div>
<div class="foo">qux</div>
<div class="foo">bazfdsfsdf</div>
<div class="foo">baz</div>'

输出将是:

<div class="bar">baz</div>
<div class="foo">qux</div>
<div class="foo">qux</div>
<div class="foo">baza</div>
<div class="foo">qux</div>
<div class="foo">bazfdsfsdf</div>
<div class="bar">baz</div>

我会这样做:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<div class="bar">baz</div>
<div class="foo">qux</div>
<div class="foo">baz</div>
EOT

target_text = doc.at('.bar').text # => "baz"
doc.search("//div[text()='#{target_text}']").each do |div|
  div['class'] = 'bar'
end

这导致:

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

没有人说我们不能混合使用 CSS 和 XPath 选择器。 XPath 有更多的功能,但它在视觉上很嘈杂,所以我在可以的时候使用 CSS,在必须的时候使用 XPath。

XPath 可以轻松地在所有节点中搜索文本,因此它是该任务的不错选择。