一个简单的问题:
<table>
<tr>
<th>foo</th>
<td><p>bar</p></td>
</tr>
</table>
details = doc.css('table > tr > th')
details2 = doc.css('table > tr > td > p')
details = details.map { |n| { name: n.text }}
details2 = details2.map { |n| { value: n.text }}
如何在一个map
语句中合并这些Nokogiri对象?
输出:
{:name=>"abc"}
{:name=>"ghj"}
{:name=>"lmn"}
{:value=>"123"}
{:value=>"456"}
{:value=>"789"}
我需要这样的东西:
{:name=>"abc", :value=>"123"}
我试过这样的事情:
details = details.map { |n| { name: n.text, value: n.css('table > tr > td > p').map { |x| {value: x} }}}
details = details.map { |n| {name: n.text, value: n.css('table > tr > td').attr('p').to_s} }
答案 0 :(得分:2)
CSS支持多个选择器,Nokogiri使用CSS尊重:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html>
<body>
<table>
<tr>
<th>foo</th>
<td><p>bar</p></td>
</tr>
</table>
</body>
</html>
EOT
text = doc.search('table tr th, table tr td p').map(&:text)
text # => ["foo", "bar"]
或者更干净一点:
rows = doc.search('table tr')
text = rows.search('th, td p').map(&:text)
text # => ["foo", "bar"]
请注意,多个选择器按顺序工作。换句话说,他们找到第一个选择器,然后找到第二个选择器等,所以如果您需要知道文档中发生的实际顺序,您必须使用单个搜索或查看实际节点来确定它们的位置在DOM中。
另请注意,我使用的是通用search
而不是更具体的css
。 Nokogiri在使用CSS或XPath时大部分时间都做得很聪明,所以使用search
或at
会更方便。
答案 1 :(得分:1)
假设数组包含有效/相同顺序的对象:
details.zip(details2).map { |e| e.inject &:merge }
答案 2 :(得分:0)
最简单的方法:
details = doc.css('table > tr > th')
details2 = doc.css('table > tr > td > p')
details.map!.with_index { |d, i| {name: d.text, value: details2[i].text } }
details
看起来像[{name: 'asd', value: '123'}, {name: 'qwe', value: '234'}]