ruby 如何使用Rails和Nokogiri找到直接子级而不是嵌套子级?

esbemjvw  于 2023-11-18  发布在  Ruby
关注(0)|答案(3)|浏览(155)

我正在使用Rails 4.2.7和Ruby(2.3)以及Nokogiri。我如何找到表的最直接的tr子级,而不是嵌套的子级?目前我在表中找到表行,如下所示。

  1. tables = doc.css('table')
  2. tables.each do |table|
  3. rows = table.css('tr')

字符串
这不仅可以找到表的直接行,例如。

  1. <table>
  2. <tbody>
  3. <tr></tr>


但是它也在行中找到行,例如,

  1. <table>
  2. <tbody>
  3. <tr>
  4. <td>
  5. <table>
  6. <tr>This is found</tr>
  7. </table>
  8. </td>
  9. </tr>


如何优化搜索以只查找直接的tr元素?

k5ifujac

k5ifujac1#

你可以使用table通过几个步骤来完成。首先,你需要找到table的“级别”(即它在其他表中的嵌套程度),然后找到所有具有相同数量的table祖先的后代tr

  1. tables = doc.xpath('//table')
  2. tables.each do |table|
  3. level = table.xpath('count(ancestor-or-self::table)')
  4. rows = table.xpath(".//tr[count(ancestor::table) = #{level}]")
  5. # do what you want with rows...
  6. end

字符串
在更一般的情况下,你可能有tr直接嵌套其他tr s,你可以这样做(这将是无效的HTML,但你可能有XML或其他一些标签):

  1. tables.each do |table|
  2. # Find the first descendant tr, and determine its level. This
  3. # will be a "top-level" tr for this table. "level" here means how
  4. # many tr elements (including itself) are between it and the
  5. # document root.
  6. level = table.xpath("count(descendant::tr[1]/ancestor-or-self::tr)")
  7. # Now find all descendant trs that have that same level. Since
  8. # the table itself is at a fixed level, this means all these nodes
  9. # will be "top-level" rows for this table.
  10. rows = table.xpath(".//tr[count(ancestor-or-self::tr) = #{level}]")
  11. # handle rows...
  12. end


第一步可以分为两个独立的查询,这可能更清楚:

  1. first_tr = table.at_xpath(".//tr")
  2. level = first_tr.xpath("count(ancestor-or-self::tr)")


(This如果有一个表没有tr s,则会失败,因为first_tr将是nil。上面的组合方法可以正确处理这种情况。)

展开查看全部
unhi4e5o

unhi4e5o2#

我不知道这是否可以直接用css/xpath来完成,所以我写了一个小方法来递归地查找节点,一旦找到就停止递归。

  1. xml= %q{
  2. <root>
  3. <table>
  4. <tbody>
  5. <tr nested="false">
  6. <td>
  7. <table>
  8. <tr nested="true">
  9. This is found</tr>
  10. </table>
  11. </td>
  12. </tr>
  13. </tbody>
  14. </table>
  15. <another_table>
  16. <tr nested = "false">
  17. <tr nested = "true">
  18. </tr>
  19. </another_table>
  20. <tr nested = "false"/>
  21. </root>
  22. }
  23. require 'nokogiri'
  24. doc = Nokogiri::XML.parse(xml)
  25. class Nokogiri::XML::Node
  26. def first_children_found(desired_node)
  27. if name == desired_node
  28. [self]
  29. else
  30. element_children.map{|child|
  31. child.first_children_found(desired_node)
  32. }.flatten
  33. end
  34. end
  35. end
  36. doc.first_children_found('tr').each do |tr|
  37. puts tr["nested"]
  38. end
  39. #=>
  40. # false
  41. # false
  42. # false

字符串

展开查看全部
qc6wkl3g

qc6wkl3g3#

你要试试这个吗?

  1. tables = doc.css('table')
  2. tables.each do |table|
  3. rows = table.css('tr')
  4. rows.each do |row|
  5. if row.parent.parent == table
  6. # Some action here...
  7. end
  8. end
  9. end

字符串

相关问题