John
John

Reputation: 3

How to parse and loop through JSON sub-children

I have a JSON string:

{
 "normal_domains":[{
   "urls [
    "domain1.com",
    "domain2.com"
],
"id":3,
"find":"ama",
"type":"text"
}
],
 "premium_domains":[{
  "urls":[
   "domain3.com",
   "domain4.com"
],
 "id":1,
 "find":"amg",
 "type":"text"
  }
 ]
}

I want to output a list for each domain in the hash with corresponding attributes:

Domain type: normal_domains
Domain: domain3.com
ID: 3
Find: ama
-- for each domain --

The code I have is this, but I cannot get it working. It returns NoMethodError: undefined method [] for nil:NilClass:

from_api = '{"normal_domains":[{"urls":["domain1.com","domain2.com"],"id":3,"find":"ama","type":"text"}],"premium_domains":[{"urls":["domain3.com","domain4.com"],"id":1,"find":"amg","type":"text"}]}'
result     = JSON.parse from_api


result.each do |child|

  loop_index = 0
  child.each do |sub_child|

    puts "Domain type: #{child}"
    puts "Domain: #{sub_child[loop_index]['urls']}"
    puts "ID: #{sub_child[loop_index]['id']}"
    puts "Find: #{sub_child[loop_index]['find']}"

    loop_index += 1
  end


end

Upvotes: 0

Views: 930

Answers (2)

J.J. Hakala
J.J. Hakala

Reputation: 6214

If you want to iterate over an array in a style that is common in C i.e. using array indexes, you should do it like

urls = domain['urls']
(0..urls.length).each do |i|
    puts " URL: #{urls[i]}"
end

or at least handle the case when indexing an array element returns nil when the code tries to access data beyond what has been entered in the array. Using array indexes is often unnecessary since iterators can be used.

Using iterators, one does not need the indexes and there is no need to check if the access is beyond the boundaries of a container.

result.each do |key,value|
    puts "Domain type: #{key}"
    value.each do |domain|
        id = domain['id']
        find = domain['find']
        type = domain['type']
        puts " ID: #{id}"
        puts " Find: #{find}"
        puts " Type: #{type}"

        domain['urls'].each do |url|
            puts " URL: #{url}"
        end
    end
end

Upvotes: 0

Oss
Oss

Reputation: 4322

The hash returned from JSON.parse does not have a .each method.

Imagine your input hash in a more organized way:

{
    "normal_domains":[ {
        "urls [
        "domain1.com",
        "domain2.com"
        ],
        "id":3,
        "find":"ama",
        "type":"text"
    }],
    "premium_domains":[{
        "urls":[
        "domain3.com",
        "domain4.com"
        ],
        "id":1,
        "find":"amg",
        "type":"text"
    }]
}

You code should be:

result = JSON.parse from_api

result.keys.each do |domain_type|
  childArray = result[domain_type]
  childArray.each do |child|
    urls = child["urls"]
    urls.each do |url|
      puts "Domain type: #{domain_type}"
      puts "Domain: #{url}"
      puts "ID: #{child['id']}"
      puts "Find: #{child['find']}"          
    end
  end
end

Upvotes: 1

Related Questions