如何用Nokogiri解析连续标签?
问题描述:
我有HTML代码:如何用Nokogiri解析连续标签?
<div id="first">
<dt>Label1</dt>
<dd>Value1</dd>
<dt>Label2</dt>
<dd>Value2</dd>
...
</div>
我的代码不能正常工作。
doc.css("first").each do |item|
label = item.css("dt")
value = item.css("dd")
end
显示所有<dt>
标签的第一次,然后<dd>
标签,我需要“的标签:值”
答
首先,你的HTML应该有一个<dl>
内<dt>
和<dd>
元素:
<div id="first">
<dl>
<dt>Label1</dt>
<dd>Value1</dd>
<dt>Label2</dt>
<dd>Value2</dd>
...
</dl>
</div>
但不会改变你如何解析它。你想找到<dt>
s并迭代它们,然后在每个<dt>
你可以使用next_element
得到<dd>
;像这样:
doc = Nokogiri::HTML('<div id="first"><dl>...')
doc.css('#first').search('dt').each do |node|
puts "#{node.text}: #{node.next_element.text}"
end
这应该工作,只要结构符合您的示例。
答
看着对方的回答后,这里是做同样的事情的方式效率极低。
require 'nokogiri'
a = Nokogiri::HTML('<div id="first"><dt>Label1</dt><dd>Value1</dd><dt>Label2</dt><dd>Value2</dd></div>')
dt = []
dd = []
a.css("#first").each do |item|
item.css("dt").each {|t| dt << t.text}
item.css("dd").each {|t| dd << t.text}
end
dt.each_index do |i|
puts dt[i] + ': ' + dd[i]
end
在css引用ID你需要把#符号之前。对于一个班级来说是这样的。符号。
答
在一些<dt>
可能有多个<dd>
的假设下,要找到所有<dt>
然后(每个)寻找下一个<dt>
之前以下<dd>
。这在纯Ruby中很容易实现,但是在XPath中做起来更有趣。 ;)
鉴于此设置:
require 'nokogiri'
html = '<dl id="first">
<dt>Label1</dt><dd>Value1</dd>
<dt>Label2</dt><dd>Value2</dd>
<dt>Label3</dt><dd>Value3a</dd><dd>Value3b</dd>
<dt>Label4</dt><dd>Value4</dd>
</dl>'
doc = Nokogiri.HTML(html)
使用没有的XPath:
doc.css('dt').each do |dt|
dds = []
n = dt.next_element
begin
dds << n
n = n.next_element
end while n && n.name=='dd'
p [dt.text,dds.map(&:text)]
end
#=> ["Label1", ["Value1"]]
#=> ["Label2", ["Value2"]]
#=> ["Label3", ["Value3a", "Value3b"]]
#=> ["Label4", ["Value4"]]
使用小的XPath:
doc.css('dt').each do |dt|
dds = dt.xpath('following-sibling::*').chunk{ |n| n.name }.first.last
p [dt.text,dds.map(&:text)]
end
#=> ["Label1", ["Value1"]]
#=> ["Label2", ["Value2"]]
#=> ["Label3", ["Value3a", "Value3b"]]
#=> ["Label4", ["Value4"]]
使用Lotsa的XPath:
doc.css('dt').each do |dt|
ct = dt.xpath('count(following-sibling::dt)')
dds = dt.xpath("following-sibling::dd[count(following-sibling::dt)=#{ct}]")
p [dt.text,dds.map(&:text)]
end
#=> ["Label1", ["Value1"]]
#=> ["Label2", ["Value2"]]
#=> ["Label3", ["Value3a", "Value3b"]]
#=> ["Label4", ["Value4"]]
这是作品,谢谢你们! – jgiunta
而不是'doc.css('#first')。search('dt')。each'为什么不只是'doc.css('#first dt')。each'?还要注意,这个答案在假设在每个'
@Progrog:'.css.search'没有什么好的理由,但也许它更接近OP已经拥有的。而且我确实包括了“只要结构与您的示例相匹配就应该有效”的警告。我同意你的方法在一般情况下会更好。 (这只是我最后一个评论的拼写纠正,因为我是dun haz gud speling) –