如何用Nokogiri解析连续标签?

时间:2011-12-13 00:09:02

标签: ruby nokogiri

我有这样的HTML代码:

<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>标记,我需要“label:value”

3 个答案:

答案 0 :(得分:6)

首先,您的HTML应该在<dt>中包含<dd><dl>元素:

<div id="first">
    <dl>
        <dt>Label1</dt>
        <dd>Value1</dd>
        <dt>Label2</dt>
        <dd>Value2</dd>
        ...
    </dl>
</div>

但这不会改变你解析它的方式。您想要找到<dt>并迭代它们,然后在每个<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

只要结构符合您的示例,这应该有效。

答案 1 :(得分:5)

假设某些<dt>可能有多个<dd>,您希望找到所有<dt>,然后(对于每个)在下一个<dd>之前找到<dt> 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) {1}}。这在纯Ruby中非常容易,但在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"]]

使用Little 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"]]

使用Lotsa XPath

{{1}}

答案 2 :(得分:1)

在看完其他答案后,这是一种做同样事情的低效方法。

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,你需要先放入#符号。对于一个类,它是。符号。