sayth sayth - 5 months ago 11
Ruby Question

nokogiri each attribute in id - @id in both nodes

I have an XML that follows this structure

<meeting id="42977">
<race id="215411">
<nomination number="8" saddlecloth="8" horse="Chipanda" id="198926" />
<nomination number="2" saddlecloth="2" horse="Chifries" id="198965" />
<nomination number="1" saddlecloth="1" horse="Itpanda" id="199260" />
</race>
<race id="215412">
<nomination number="1" saddlecloth="1" horse="Ruby" id="199634" />
<nomination number="2" saddlecloth="2" horse="Gems" id="208926" />
<nomination number="3" saddlecloth="3" horse="Rock" id="122923" />
</race>
</meeting>


I want to be able to extract the nomination id attribute and keep it assosciated to the race id that it came from so that output would be printed, I would really be putting this into a database later.

RaceID NomID
215411 198926
215411 198965
215411 199260
215412 199634
215412 208926
215412 122923


Tried a few different routes but cannot get it to work using a css selector such as @doc.css('race id') actually collects all ids in the document that are descendants of race.

This is where I have gone so far

require 'nokogiri'

@doc = Nokogiri::XML(File.open("data/20160521RHIL0.xml"))
#puts @doc.xpath("//race/nomination/@horse")
race = @doc.xpath("//race")
#nom_id = @doc.xpath("//race/nomination/@id")

race.each do |f|
f.xpath('//@id | //nomination/@id').each do |node|
puts node['V']
end
end
#node_num = race_id.length
#(1..node_num).each do |x|
#nom_id.each do |y|
#puts "race ID\t" + "#{race_id[x]} " + "nom_id\t" + "#{y}"
#end
#end

Answer

I preffer to use hash like export, so you can use something like this.

xml = '<meeting id="42977">
<race id="215411">
<nomination number="8" saddlecloth="8" horse="Chipanda" id="198926" />
<nomination number="2" saddlecloth="2" horse="Chifries" id="198965" />
<nomination number="1" saddlecloth="1" horse="Itpanda" id="199260" />
<race id="215412">
<nomination number="1" saddlecloth="1" horse="Ruby" id="199634" />
<nomination number="2" saddlecloth="2" horse="Gems" id="208926" />
<nomination number="3" saddlecloth="3" horse="Rock" id="122923" />
</race>
</meeting>'

require 'nokogiri'

doc = Nokogiri::XML(xml)

races = doc.xpath("//race")

export = races.each_with_object(Hash.new { |k, v| k[v] = [] }) do |elem, exp|
  elem.xpath("./nomination").each do |nom_elem|
    exp[elem['id']] << nom_elem['id']
  end
end

output

p export

# {
#   "215411"=>["198926", "198965", "199260"],
#   "215412"=>["199634", "208926", "122923"]
# }

I hope this helps

Comments