简体   繁体   中英

How do I read JSON received from a REST API?

I'm trying to read some JSON that I received from a REST API but I'm having some issues.

To get my JSON, I'm using Open::URI. I created my request like this:

require "open-uri"
require "json"
content = open("http://foo.bar/test.json").read
result = JSON.parse(content)

At this point my JSON is supposed to be parsed from a string, and so if I correctly understood, a hash containing my JSON is built assuming the JSON I received has a structure that looks like this:

{
   "root":
   {
       "foos":
       {
           "1":
           {
               "title" : "zero",
               "number" : 0
           },
           "2":
           {
               "title" : "twenty",
               "number" : 20
           },
           ...
       }
    }
}

I would like to iterate over each foos and, for each of them, get the title and the number. I tried this:

content["root"]["foos"].each do |foo| puts foo.title + " " + foo.number end

But, as output, I got:

#<Enumerator:0x007fceb8b33718>

Where is/are my mistake(s)?

Thanks in advance,

Here's an option... Iterate over the keys inside of the foos object.

json = JSON.parse(your_sample_json)
 => {"root"=>{"foos"=>{"1"=>{"title"=>"zero", "number"=>0}, "2"=>{"title"=>"twenty", "number"=>20}}}}

foos = json["root"]["foos"]
 => {"1"=>{"title"=>"zero", "number"=>0}, "2"=>{"title"=>"twenty", "number"=>20}}

foos.keys.each { |key| puts foos[key]["title"] }
zero
twenty

Also, if you have control over the JSON object you're parsing, you could make foos an array instead of a bunch of numbered objects.

I'd do it like this:

require 'json'
require 'pp'

hash = JSON.parse(
  '{
    "root": {
      "foos": {
        "1": {
          "title": "zero",
          "number": 0
        },
        "2": {
          "title": "twenty",
          "number": 20
        }
      }
    }
  }'
)

results = hash['root']['foos'].map{ |k, v|
  [v['title'], v['number']]
}

pp results

After running it outputs an array of arrays:

[["zero", 0], ["twenty", 20]]

map might behave a bit differently than you'd expect with a hash; It assigns each key/value of the hash as an array of two elements. The key is the first element, the value is the second. Because your structure is a hash of hashes of hashes of hashes, when iterating over hash['root']['foos'] the values for keys "1" and "2" are a hash, so you can access their values like you would a hash.

Back to your code:

hash["root"]["foos"].each do |foo|
  puts foo.title + " " + foo.number
end

won't work. It doesn't return an enumerator at all, so that part of the question is inaccurate. What your code returns is:

undefined method `title' for ["1", {"title"=>"zero", "number"=>0}]:Array (NoMethodError)

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