Nokogiri:选择元素A和B之间的内容

Jav*_*ier 4 ruby parsing dom ruby-on-rails nokogiri

让Nokogiri选择start和stop元素之间的所有内容(包括start/stop-element)最聪明的方法是什么?

检查下面的示例代码,了解我在寻找什么:

require 'rubygems'
require 'nokogiri'

value = Nokogiri::HTML.parse(<<-HTML_END)
  "<html>
    <body>
      <p id='para-1'>A</p>
      <div class='block' id='X1'>
        <p class="this">Foo</p>
        <p id='para-2'>B</p>
      </div>
      <p id='para-3'>C</p>
      <p class="that">Bar</p>
      <p id='para-4'>D</p>
      <p id='para-5'>E</p>
      <div class='block' id='X2'>
        <p id='para-6'>F</p>
      </div>
      <p id='para-7'>F</p>
      <p id='para-8'>G</p>
    </body>
  </html>"
HTML_END

parent = value.css('body').first

# START element
@start_element = parent.at('p#para-3')
# STOP element
@end_element = parent.at('p#para-7')
Run Code Online (Sandbox Code Playgroud)

结果(返回值)应如下所示:

<p id='para-3'>C</p>
<p class="that">Bar</p>
<p id='para-4'>D</p>
<p id='para-5'>E</p>
<div class='block' id='X2'>
  <p id='para-6'>F</p>
</div>
<p id='para-7'>F</p>
Run Code Online (Sandbox Code Playgroud)

更新:这是我目前的解决方案,但我认为必须有更聪明的东西:

@my_content = ""
@selected_node = true

def collect_content(_start)

  if _start == @end_element
    @my_content << _start.to_html
    @selected_node = false
  end

  if @selected_node == true
    @my_content << _start.to_html
    collect_content(_start.next)
  end

end

collect_content(@start_element)

puts @my_content
Run Code Online (Sandbox Code Playgroud)

Mag*_*olm 10

一种使用递归的太聪明的oneliner:

def collect_between(first, last)
  first == last ? [first] : [first, *collect_between(first.next, last)]
end
Run Code Online (Sandbox Code Playgroud)

迭代解决方案:

def collect_between(first, last)
  result = [first]
  until first == last
    first = first.next
    result << first
  end
  result
end
Run Code Online (Sandbox Code Playgroud)

编辑:(简短)解释星号

它被称为splat运算符.它"展开"一个数组:

array = [3, 2, 1]
[4, array]  # => [4, [3, 2, 1]]
[4, *array] # => [4, 3, 2, 1]

some_method(array)  # => some_method([3, 2, 1])
some_method(*array) # => some_method(3, 2, 1)

def other_method(*array); array; end
other_method(1, 2, 3) # => [1, 2, 3] 
Run Code Online (Sandbox Code Playgroud)