Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 如何使用Nokogiri解析连续标记?_Ruby_Nokogiri - Fatal编程技术网

Ruby 如何使用Nokogiri解析连续标记?

Ruby 如何使用Nokogiri解析连续标记?,ruby,nokogiri,Ruby,Nokogiri,我有如下HTML代码: <div id="first"> <dt>Label1</dt> <dd>Value1</dd> <dt>Label2</dt> <dd>Value2</dd> ... </div> doc = Nokogiri::HTML('<div id="first"><dl>...') doc.css('#first').searc

我有如下HTML代码:

<div id="first">
<dt>Label1</dt>
<dd>Value1</dd>

<dt>Label2</dt>
<dd>Value2</dd>

...
</div>
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
需要“nokogiri”
a=Nokogiri::HTML('Label1Value1Label2Value2')
dt=[]
dd=[]
a、 css(“#第一”)。每个do |项|

css(“dt”)。每个{t | dt首先,您的HTML应该在
中包含
元素:


只要结构与您的示例相匹配,这应该是可行的。

假设某些
可能有多个
,您希望找到所有
,然后(针对每个)在下一个
之前查找以下
。这在纯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)
使用Lotsa 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"]]
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"]]
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"]]

请注意,由于
“#first”
只能匹配一个元素,因此您拥有的元素与:
item=a.at_css(“#first”)相等(但更差)
。在外部使用每个
是完全多余的。此外,请注意,此答案假设
之间始终存在1-1配对。虽然原始问题标记是如此,但在现实世界的标记中可能并不总是如此。最后,通过迭代两个配对数组,您可以不要考虑使用<代码> Dt.zip(DD)。每个{ dt,d}…} /代码>而不是<代码> EACHYORY索引>代码>,而不是<代码> docs.css('y'第一)。.each?还要注意,这个答案是基于这样一个假设的,即每个
之后总是有一个且只有一个
(这在一般HTML中可能不是这样)。@Phrogz:earch.css没有什么好的理由,也许它更接近OP已经拥有的内容。我确实包括了一个“只要结构与您的示例相匹配,这应该是有效的”警告。我同意您的方法在一般情况下会更有效。(这只是我上一次评论的拼写更正,因为我不知道haz gud speling)
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"]]
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"]]