Jav*_*ier 7 ruby xpath dom ruby-on-rails nokogiri
我正在尝试填补变量parent_element_h1和parent_element_h2.任何人都可以帮助我使用Nokogiri将我需要的信息输入到这些变量中吗?
require 'rubygems'
require 'nokogiri'
value = Nokogiri::HTML.parse(<<-HTML_END)
"<html>
<body>
<p id='para-1'>A</p>
<div class='block' id='X1'>
<h1>Foo</h1>
<p id='para-2'>B</p>
</div>
<p id='para-3'>C</p>
<h2>Bar</h2>
<p id='para-4'>D</p>
<p id='para-5'>E</p>
<div class='block' id='X2'>
<p id='para-6'>F</p>
</div>
</body>
</html>"
HTML_END
parent = value.css('body').first
# start_here is given: A Nokogiri::XML::Element of the <div> with the id 'X2
start_here = parent.at('div.block#X2')
# this should be a Nokogiri::XML::Element of the nearest, previous h1.
# in this example it's the one with the value 'Foo'
parent_element_h1 =
# this should be a Nokogiri::XML::Element of the nearest, previous h2.
# in this example it's the one with the value 'Bar'
parent_element_h2 =
Run Code Online (Sandbox Code Playgroud)
请注意:start_here元素可以位于文档中的任何位置.HTML数据只是一个例子.这就是说,头部<h1>和<h2>可能是兄弟姐妹start_here或兄弟姐妹的孩子start_here.
下面的递归方法是一个很好的起点,但它不起作用,<h1>因为它是一个兄弟的孩子start_here:
def search_element(_block,_style)
unless _block.nil?
if _block.name == _style
return _block
else
search_element(_block.previous,_style)
end
else
return false
end
end
parent_element_h1 = search_element(start_here,'h1')
parent_element_h2 = search_element(start_here,'h2')
Run Code Online (Sandbox Code Playgroud)
接受答案后,我想出了自己的解决方案.它就像一个魅力,我觉得它非常酷.
Aar*_*nni 10
我将采用的方法(如果我理解你的问题)是使用XPath或CSS来搜索你的"start_here"元素和你想要搜索的父元素.然后,从父级开始递归地遍历树,当你点击"start_here"元素时停止,并保持与你的风格匹配的最后一个元素.
就像是:
parent = value.search("//body").first
div = value.search("//div[@id = 'X2']").first
find = FindPriorTo.new(div)
assert_equal('Foo', find.find_from(parent, 'h1').text)
assert_equal('Bar', find.find_from(parent, 'h2').text)
Run Code Online (Sandbox Code Playgroud)
哪里FindPriorTo是处理递归的简单类:
class FindPriorTo
def initialize(stop_element)
@stop_element = stop_element
end
def find_from(parent, style)
@should_stop = nil
@last_style = nil
recursive_search(parent, style)
end
def recursive_search(parent, style)
parent.children.each do |ch|
recursive_search(ch, style)
return @last_style if @should_stop
@should_stop = (ch == @stop_element)
@last_style = ch if ch.name == style
end
@last_style
end
end
Run Code Online (Sandbox Code Playgroud)
如果这种方法不够灵活,那么你可以通过重写recursive_search不使用递归来优化事物,并传递你正在寻找的两种样式并跟踪最后找到的样式,所以你没有额外的时间穿越树.
我还会说在尝试解析文档时尝试使用Monkey修补Node来挂钩,但看起来所有这些都是用C编写的.也许你可能会更好地使用Nokogiri之外的东西,它有一个原生的Ruby SAX解析器(也许是REXML),或者如果速度是您真正关心的问题,请使用Xerces或类似工具在C/C++中进行搜索.我不知道这些将如何处理解析HTML.
我想我发现这个已经晚了几年,但我觉得有必要发帖,因为所有其他解决方案都太复杂了。
这是带有 XPath 的单个语句:
start = doc.at('div.block#X2')
start.at_xpath('(preceding-sibling::h1 | preceding-sibling::*//h1)[last()]')
#=> <h2>Foo</h2>
start.at_xpath('(preceding-sibling::h2 | preceding-sibling::*//h2)[last()]')
#=> <h2>Bar</h2>
Run Code Online (Sandbox Code Playgroud)
这可以容纳以前的直接兄弟姐妹或以前兄弟姐妹的孩子。无论匹配哪一个,last()谓词都会确保您获得最接近的上一个匹配项。
| 归档时间: |
|
| 查看次数: |
13842 次 |
| 最近记录: |