【问题标题】:How to select the smallest element that contains text如何选择包含文本的最小元素
【发布时间】:2017-03-21 04:29:45
【问题描述】:

我正在使用带有 Nokogiri 的 Rails 5。如何选择包含文本的最小元素?

我的页面上有这个元素:

<td class="style35" style="font-size: medium; border: thin solid #000000">
                        Location</td>

我想我可以使用:

doc.at('td:contains("Location")')

取而代之的是,包含包含此元素的表的包装 td:

<td><span class="myClass"><table> ....

编写选择包含我想要的文本的最小(最小?)元素的表达式的正确方法是什么?

【问题讨论】:

  • 不是“NOkogiri”,而是“Nokogiri”,“seleted”是“selected”,“teh”是“the”,“ocntains”是“contains”。语法和拼写对 SO 很重要。您的问题是参考页面的开始,而答案是问题的解决方案,就像百科全书或食谱中的页面一样。
  • 请阅读“minimal reproducible example”。你需要给我们一个最小的 HTML 示例,它可以展示问题,在一个片段中,而不是在单独的块中。不要让我们重建它。

标签: ruby-on-rails ruby css-selectors nokogiri


【解决方案1】:

如果你使用at 方法,它只会返回第一个结果。

css 方法将返回与 CSS 选择器匹配的所有元素,包括正确的 td 元素和环绕整个表格的 td 元素。

如果你使用这样的东西,它会找到所有的td标签,包含单词Location,然后它将没有包裹在另一个td标签周围的元素存储在一个数组中:

td_with_no_child_and_have_location = []

doc.css("td:contains('Location')").each do |td_element| 
    if td_element.css("td").empty? 
        td_with_no_child_and_have_location << td_element
    end
end

first_td = td_with_no_child_and_have_location.first

【讨论】:

  • 我没有很好地解释自己。我不想要 HTML 最少的 TD,我想要没有其他子 TD 且其文本包含“位置”一词的 TD。
  • 我更新了我的答案,以便它存储符合您条件的元素数组。然后你可以使用该数组的第一个元素,如果你知道你的元素将永远是第一个。
  • 感谢此次更新。有没有办法编写一个 CSS 选择器,在一行中完成你对循环所做的事情?
  • 是的,您可以使用doc.css("td td:contains('Location')"),但这只会确保它是第二个 td 标记,而不是大树中的最后一个。如果您在原始表格中只有一张表格,那就可以了。
【解决方案2】:

如果您不向我们提供最低限度的 HTML,我们将很难为您提供帮助。我尝试重新创建它,但 YMMV:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<html><body><table><tr>
<td><span class="myClass"><table><tr>
      <td class="style35" style="font-size: medium; border: thin solid #000000">
        Location</td>
</tr></table></td></tr></table></html>
EOT
doc.at('.myClass td.style35').text # => "\n        Location"

如果您想要的标签嵌入到另一个表中,则利用其他一些特征来帮助您导航,例如类信息。

在这种情况下使用at 应该会有所帮助,因为通常表格的标题会在包含第一个单元格的第一行中。 at 相当于 search('some selector').first

上面的选择器甚至可以写成.myCLass .style35td td,这样可以在另一个td 中找到td。将它与at 结合起来,您将得到第一个这样的事件:

doc.at('.myClass td.style35').text # => "\n        Location"
doc.at('.myClass .style35').text # => "\n        Location"
doc.at('td td').text # => "\n        Location"

【讨论】:

  • 我正在寻找更通用的东西。 TD 并不总是将“myClass”作为一个类。我正在寻找包含给定文本的 TD,其中没有其他 TD。
  • 您需要在问题中提供更多信息。它非常广泛,不符合“minimal reproducible example”中的准则。我们不能投票,因为你有赏金。如果您在事先不知道该标题或文档结构是什么的情况下尝试编写一个通用的“总能找到一个标题”单元格,那么您将遇到困难。
【解决方案3】:

选择所有td 元素,按内容长度排序并选择第一个元素。根据需要更改选择器。排序默认为升序。所以你首先得到最小的元素。

doc.css('td').sort_by do |td_element|
  l.text.length
end.first

【讨论】:

  • 你的逻辑不适用于我的情况。表达式 "doc.at('td:contains("Location")'" 只返回一个元素。运行 "doc.at('td:contains("Location")').at('td:contains ("Location")')" 为我提供了此特定案例所需的元素,但一般来说,我不知道要深入多少级别才能找到我要查找的内容。
  • 这不是很好的逻辑。后续单元格可能包含比所需字符串更短的字符串。此外,您的示例代码无效。我建议您针对示例 HTML 测试您的代码并显示您的结果。
猜你喜欢
  • 2021-10-03
  • 2020-08-02
  • 2017-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-21
  • 1970-01-01
  • 2020-05-27
相关资源
最近更新 更多