Вот простое решение, которое дает вам NodeSet
s со всеми узлами между <sup … class="v">
, хэшированными их id
.
doc = Nokogiri.HTML(your_html)
nodes_by_vsup_id = Hash.new{ |k,v| k[v]=Nokogiri::XML::NodeSet.new(doc) }
last_id = nil
doc.at('body').children.each do |n|
last_id = n['id'] if n['class']=='v'
nodes_by_vsup_id[last_id] << n
end
puts nodes_by_vsup_id['21']
#=> <sup class="v" id="21">
#=> 2
#=> </sup>
#=>
#=> now this is a different section
#=> <p></p>
#=>
#=> how do we keep this separate
#=> <sup class="footnote" value="fn2">
#=> [x]
#=> </sup>
В качестве альтернативы, если вы не хотите, чтобы разделитель 'sup' был частью коллекции, вместо этого выполните:
doc.at('body').elements.each do |n|
if n['class']=='v'
last_id = n['id']
else
nodes_by_vsup_id[last_id] << n
end
end
Вот альтернативное, даже более общее решение:
class Nokogiri::XML::NodeSet
# Yields each node in the set to your block
# Returns a hash keyed by whatever your block returns
# Any nodes that return nil/false are grouped with the previous valid value
def group_chunks
Hash.new{ |k,v| k[v] = self.class.new(document) }.tap do |result|
key = nil
each{ |n| result[key = yield(n) || key] << n }
end
end
end
root_items = doc.at('body').children
separated = root_items.group_chunks{ |node| node['class']=='v' && node['id'] }
puts separated['21']