如何获取特定标记之后的所有节点

时间:2015-04-19 06:53:17

标签: html ruby-on-rails ruby nokogiri

我有以下HTML结构,我想找到<div>xyz</div>之后的所有兄弟节点和节点,直到HTML的最后一个节点:

<html>
  <head>
  </head>
  <body>
    <div id="page-container">
     <div id="page-1">
       <p> abc <p>
       <div>xyz</div>
       <p>bbb</p>
       <b>hhhh</b>
     </div>
     <div  id="page-2">
      <p>hhhh</p>
      <span>abc</span>
      <p> gggg </p>
     </div>
     <div  id="page-3">
      <p>hhhh</p>
      <span>abc</span>
      <p> gggg </p>
     </div>
    </div>
  </body>
</html>

我用过

xpath('//div[contains(text(), "xyz")]/following-sibling::*')

但它没有返回所有节点,它只提供<p>bbb</p><b>hhhh</b>个节点。

我期待以下输出:

<div id="page-container">
  <div id="page-1">
     <div>xyz</div>
      <p>bbb</p>
      <b>hhhh</b>
     </div>
   <div  id="page-2">
     <p>hhhh</p>
     <span>abc</span>
     <p> gggg </p>
   </div>
   <div  id="page-3">
     <p>hhhh</p>
     <span>abc</span>
     <p> gggg </p>
   </div>
 </div>

如何获取特定节点之后出现的所有节点?

1 个答案:

答案 0 :(得分:0)

从HTML或XML中提取信息最困难的事情之一是确定从哪里开始捕获。如果你想要捕获大量类似的节点,然后删除你不想要的东西,那么通常更容易从所需的节点开始,然后删除它,而不是零碎地工作并尝试重建某些结构。

我会这样做:

require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html>
  <head>
  </head>
  <body>
    <div id="page-container">
     <div id="page-1">
       <p> abc <p>
       <div>xyz</div>
       <p>bbb</p>
       <b>hhhh</b>
     </div>
     <div  id="page-2">
      <p>hhhh</p>
      <span>abc</span>
      <p> gggg </p>
     </div>
     <div  id="page-3">
      <p>hhhh</p>
      <span>abc</span>
      <p> gggg </p>
     </div>
    </div>
  </body>
</html>
EOT

page_container = doc.at('#page-container')
page1 = page_container.at('#page-1')
page1.children = page1.children[3..-1]

结果是:

puts page_container.to_html
# >> <div id="page-container">
# >>      <div id="page-1">
# >> <div>xyz</div>
# >>        <p>bbb</p>
# >>        <b>hhhh</b>
# >>      </div>
# >>      <div id="page-2">
# >>       <p>hhhh</p>
# >>       <span>abc</span>
# >>       <p> gggg </p>
# >>      </div>
# >>      <div id="page-3">
# >>       <p>hhhh</p>
# >>       <span>abc</span>
# >>       <p> gggg </p>
# >>      </div>
# >>     </div>

注意:

  • 我使用的是CSS选择器,而不是XPath。 CSS几乎总是更具可读性; XPath具有更强大的功能,但这需要以可读性为代价。
  • 我在“page-1”div中使用偏移量跳过前三个节点:有一个文本节点,<p>节点后跟另一个文本节点:

    page_container.at('#page-1').children[0,3]
    # => [#<Nokogiri::XML::Text:0x3fdb6d196b48 "\n       ">, #<Nokogiri::XML::Element:0x3fdb6d1979a8 name="p" children=[#<Nokogiri::XML::Text:0x3fdb6d1b7d48 " abc ">]>, #<Nokogiri::XML::Element:0x3fdb6d1b7af0 name="p" children=[#<Nokogiri::XML::Text:0x3fdb6d1b7870 "\n       ">]>]
    
  • 我通常使用remove来摆脱<p> abc <p>,但我看到的是Nokogiri 1.6.6.2中的错误导致:

    page_container.at('#page-1 p').remove
    
    puts page_container.to_html
    # >> <div id="page-container">
    # >>      <div id="page-1">
    # >>        <p>
    # >>        </p>
    # >> <div>xyz</div>
    

    已为此创建错误报告。