Cherry使用Nokogiri按特定顺序选择XML节点

时间:2018-08-21 13:44:43

标签: ruby xml ruby-on-rails-4 xpath nokogiri

我需要以特定顺序(橙色,苹果,樱桃)导入水果节点,而不是字母或数字:

<fruits>
  <fruit>
    <name>Apple</name>
    <expiration>2018-08-21</expiration>
  </fruit>
  <fruit>
    <name>Banana</name>
    <expiration>2018-08-29</expiration>
  </fruit>
  <fruit>
    <name>Cherry</name>
    <expiration>2018-08-29</expiration>
  </fruit>
  <fruit>
    <name>Orange</name>
    <expiration>2018-08-20</expiration>
  </fruit>
</fruits>

在新的排序要求之前,我们通过这样的节点进行枚举,并且效果很好:

doc.css('fruit').each do |fruit|
  Pantry.create({name:fruit.css('name').first.text,
                 expiration: fruit.css('expiration').text})
end

我尝试基于this answer使用xpath,但是它仅返回name子节点,而不返回父fruit节点,从而导致expiration子节点无法访问:

fruit_basket = %w[Orange Apple Cherry]
fruit_basket.each do |temp_fruit|  
  fruit = doc.xpath("//name[contains(text(), '#{temp_fruit}')]")
  Pantry.create({name:fruit.css('name').text,
                 expiration: fruit.css('expiration').text})
end

fruit_basket数组的顺序枚举水果节点的正确方法(nokogiri方式?)是什么,而忽略不在fruit_basket中的水果节点? / strong>

1 个答案:

答案 0 :(得分:0)

Nokogiri返回一个Enumerable,您可以根据需要对其进行排序:

fruit_basket = %w[Orange Apple Cherry]

doc.
  xpath('//fruit').
  sort_by do |e| # HERE
    fruit_basket.index(e.xpath('name').text) || Float::INFINITY
  end.
  each { |e| puts e.text }

#⇒ Orange
#  2018-08-20
#  Apple
#  2018-08-21
#  Cherry
#  2018-08-29
#  Banana
#  2018-08-29

是否需要跳过未列出的水果,请提前对其进行过滤:

doc.
  xpath('//fruit').
  select do |e| # HERE
    fruit_basket.index(e.xpath('name').text)
  end.
  sort_by do |e|
    fruit_basket.index(e.xpath('name').text)
  end.
  each { |e| puts e.text }