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

esbemjvw  于 12个月前  发布在  Ruby
关注(0)|答案(3)|浏览(101)

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

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

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

<table>
    <tbody>
        <tr>…</tr>


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

<table>
    <tbody>
        <tr>
            <td>
                <table>
                    <tr>This is found</tr>
                </table>
            </td>
        </tr>


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

k5ifujac

k5ifujac1#

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

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

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

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


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

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


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

unhi4e5o

unhi4e5o2#

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

xml= %q{
<root>
  <table>
    <tbody>
      <tr nested="false">
        <td>
          <table>
            <tr nested="true">
              This is found</tr>
          </table>
        </td>
      </tr>
    </tbody>
  </table>
  <another_table>
    <tr nested = "false">
      <tr nested = "true">
    </tr>
  </another_table>
  <tr nested = "false"/>
</root>
}

require 'nokogiri'

doc = Nokogiri::XML.parse(xml)

class Nokogiri::XML::Node
  def first_children_found(desired_node)
    if name == desired_node
      [self]
    else
      element_children.map{|child|
        child.first_children_found(desired_node)
      }.flatten
    end
  end
end

doc.first_children_found('tr').each do |tr|
  puts tr["nested"]
end

#=>
# false
# false
# false

字符串

qc6wkl3g

qc6wkl3g3#

你要试试这个吗?

tables = doc.css('table')

tables.each do |table|
  rows = table.css('tr')

  rows.each do |row|
    if row.parent.parent == table
      # Some action here...
    end
  end
end

字符串

相关问题