sayth
sayth

Reputation: 7038

Nokogiri and creating a hash from two items - Error retrieves all as string

I am trying to retrieve two elements both with nine responses from an xml file with Nokogiri. Retrieval itself isn't hard:

number = @doc.xpath('//Race/@RaceNumber').text
# => "123456789"

But it selects it as one string. And this is the other reduced for brevity:

name = @doc.css('NameRaceFull')
# => [#<Nokogiri::XML::Element:0x1775154 name="NameRaceFull" attributes=[#<Nokogiri::XML::Attr:0x1774448 name="StakesGroupId" value="346">] 

My goal is to create a hash and so on for each number and name

{ 1 => "Greenland Australia Maribyrnong Trial Stakes" }

But with the retrieval pulling it all as a string, how would I get this to work?

My solution was to create two arrays and then do Hash[number.zip(name)], but if this is possible in one go, that would be great.

@doc.xpath('//Race/@RaceNumber').text.each do |name|
  arr << name
end
# => NoMethodError: undefined method `each' for "123456789":String

The example part of the XML I am getting this from is this.

<Race RaceCode="5038498" CurrentRaceStage="Results" RaceNumber="1">
      <NameRaceFull StakesGroupId="346">Greenland Australia Maribyrnong Trial Stakes</NameRaceFull>

Upvotes: 1

Views: 208

Answers (1)

joelparkerhenderson
joelparkerhenderson

Reputation: 35443

Here's how I would solve it:

hash = Hash[doc.xpath('//Race').map{|race|
  [race["RaceNumber"].to_i, race.xpath('NameRaceFull').text]
}]

The output hash:

{1=>"Foo", 2=>"Goo", 3=>"Hoo"}

The code works like this:

  1. Find all the Race items and iterate on them.
  2. Each iteration produces a key (i.e. race number) and a value (i.e. the full name).
  3. Combine the results to produce your hash.

Note that Ruby offers a variety of ways to convert items to hashes, and you can use any way you prefer. For example, Hash#[], Array#to_h, Enumerable#inject, etc.

Here's a complete code example with simplified XML for clarity:

#!/usr/bin/env ruby
require 'nokogiri'

xml=<<-qqq
<Races>
<Race RaceNumber="1"><NameRaceFull>Foo</NameRaceFull></Race>
<Race RaceNumber="2"><NameRaceFull>Goo</NameRaceFull></Race>
<Race RaceNumber="3"><NameRaceFull>Hoo</NameRaceFull></Race>
</Races>
qqq

doc=Nokogiri.parse(xml)

hash = Hash[doc.xpath('//Race').map{|race|
  [race["RaceNumber"].to_i, race.xpath('NameRaceFull').text]
}]

p hash

Upvotes: 1

Related Questions