简体   繁体   中英

Converting a ruby structure to a hash

I've got a bit of a headache here - I'm pretty new to Ruby...

I've got a structure like so returned from Savon...

{
  :item => [{
              :key =>  "result",
              :value=> "success"
            },
            {
              :key =>  "data",
              :value=> {
                  :item => [{ :key => "displayName", 
                              :value => "Matt" 
                            },
                            {
                              :key => "messages",
                              :value => { 
                                  :items => [{....}]
                            }
                       ]
               }
       }]
}

And I need to get it to be like...

{
  :result => success
  :data => [{
              :displayName => "Matt"
           },
           {
              :messages => [{
                              :messageName => "Test Message"
                           }]
           }]
}

So I can easily manipulate and navigate the data structure I've tried a few methods including just passing the value of :item ...

def convertData(data)
  result = {}
  if(data!=nil)
    data.each do |item|
      key = item[:key] 
      value = item[:value] 
      if(value.instance_of?(Hash))
        result[key] = convertData(value[:item])
      else
        result[key] = value
      end  
    end
  end
  return result
end

But this just gives me a tonne of Type errors for symbol to integer conversion (I assume that's the array index playing up). Any help much appreciated.

When trying to tackle problem like this in Ruby, it's useful to think of it in terms of transformations on your data. The Ruby Enumerable library is full of methods that help you manipulate regular data structures like Array and Hash.

A Ruby solution to this problem looks like:

def desavon(data)
  case (data)
  when Hash
    if (data[:item])
      data[:item].collect do |item|
        { item[:key] => desavon(item[:value]) }
      end
    else
      # raise error?
    end
  else
    data
  end
end

Here's some sample input data and sample output:

input = {
  item: [
    {
      key: "result",
      value: "success"
    },
    {
      key:  "data",
      value: {
        item: [
          {
            key: "displayName", 
            value: "Matt" 
          },
          {
            key: "messages",
            value: { 
              item: [
                {
                  key: 'messageName',
                  value: 'Test Message'
                }
              ]
            }
          }
        ]
      }
    }
  ]
}

desavon(input)
# => [{"result"=>"success"}, {"data"=>[{"displayName"=>"Matt"}, {"messages"=>[{"messageName"=>"Test Message"}]}]}]

I think this version looks better, output-wise, but that's a call you'll have to make:

def desavon(data)
  case (data)
  when Hash
    if (data[:item])
      Hash[
        data[:item].collect do |item|
          [ item[:key], desavon(item[:value]) ]
        end
      ]
    else
      # raise error?
    end
  else
    data
  end
end

desavon(input)
# => {"result"=>"success", "data"=>{"displayName"=>"Matt", "messages"=>{"messageName"=>"Test Message"}}}

Note that the case statement here is really the key, it allows you to quickly differentiate between different types of data you're converting, and the Hash[] method converts key-value pairs into the Hash structure you're looking for.

This is similar to your attempt, but just passes through content it doesn't recognize as-is.

Savon provides a to_hash method on the result. What I usually do is:

...

response = @client.request :wsdl, :conversion_rate do
  soap.body = {
    "FromCurrency" => from_curr,
    "ToCurrency" => to_curr
  }
end    
response.to_hash[:conversion_rate_response][:conversion_rate_result];

... full script here https://gist.github.com/sroller/3d04842ab763f52b6623

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM