Parsing a JSON string in Ruby

RubyJson

Ruby Problem Overview


I have a string that I want to parse in Ruby:

string = '{"desc":{"someKey":"someValue","anotherKey":"value"},"main_item":{"stats":{"a":8,"b":12,"c":10}}}'

Is there an easy way to extract the data?

Ruby Solutions


Solution 1 - Ruby

This looks like JavaScript Object Notation (JSON). You can parse JSON that resides in some variable, e.g. json_string, like so:

require 'json'
JSON.parse(json_string)

If you’re using an older Ruby, you may need to install the json gem.


There are also other implementations of JSON for Ruby that may fit some use-cases better:

Solution 2 - Ruby

Just to extend the answers a bit with what to do with the parsed object:

# JSON Parsing example
require "rubygems" # don't need this if you're Ruby v1.9.3 or higher
require "json"

string = '{"desc":{"someKey":"someValue","anotherKey":"value"},"main_item":{"stats":{"a":8,"b":12,"c":10}}}'
parsed = JSON.parse(string) # returns a hash

p parsed["desc"]["someKey"]
p parsed["main_item"]["stats"]["a"]

# Read JSON from a file, iterate over objects
file = open("shops.json")
json = file.read

parsed = JSON.parse(json)

parsed["shop"].each do |shop|
  p shop["id"]
end

Solution 3 - Ruby

As of Ruby v1.9.3 you don't need to install any Gems in order to parse JSON, simply use require 'json':

require 'json'

json = JSON.parse '{"foo":"bar", "ping":"pong"}'
puts json['foo'] # prints "bar"

See JSON at Ruby-Doc.

Solution 4 - Ruby

It looks like a JSON string. You can use one of many JSON libraries and it's as simple as doing:

JSON.parse(string)

Solution 5 - Ruby

This is a bit late but I ran into something interesting that seems important to contribute.

I accidentally wrote this code, and it seems to work:

require 'yaml'
CONFIG_FILE = ENV['CONFIG_FILE'] # path to a JSON config file 
configs = YAML.load_file("#{CONFIG_FILE}")
puts configs['desc']['someKey']

I was surprised to see it works since I am using the YAML library, but it works.

The reason why it is important is that yaml comes built-in with Ruby so there's no gem install.

I am using versions 1.8.x and 1.9.x - so the json library is not built in, but it is in version 2.x.

So technically - this is the easiest way to extract the data in version lower than 2.0.

Solution 6 - Ruby

Don't see any answers here that mention parsing directly to an object other than a Hash, but it is possible using the poorly-documented object_class option(see https://ruby-doc.org/stdlib-2.7.1/libdoc/json/rdoc/JSON.html):

JSON.parse('{"foo":{"bar": 2}}', object_class: OpenStruct).foo.bar
=> 2

The better way to read that option is "The ruby class that a json object turns into", which explains why it defaults to Hash. Likewise, there is an array_class option for json arrays.

Solution 7 - Ruby

I suggest Oj as it is waaaaaay faster than the standard JSON library.

https://github.com/ohler55/oj

(see performance comparisons here)

Solution 8 - Ruby

If you want to deserialise to your own class instead of OpenStruct it doesn't take a lot of work to make the following possible:

require 'json'
# result is an instance of MyClass
result = JSON.parse(some_json_string, object_class: MyClass)

All you have to do is to provide a zero-argument constructor and implement the #[]= method which JSON.parse will call. If you don't want to expose it, it's sufficient to let it be private:

class MyClass
  attr_reader :a, :b

  private

  def []=(key, value)
    case key
    when 'a' then @a = value
    when 'b' then @b = value
    end
  end
end

Trying it out in irb:

> JSON.parse('{"a":1, "b":2}', object_class: MyClass)
=> #<MyClass:0x00007fe00913ae98 @a=1, @b=2>

A caveat with this approach is that it only works for flat structures, because the object_class argument really tells the parser what class it should use to deserialise JSON objects in the string instead of Hash (see the similar argument array_class for the analogous operation for JSON arrays). For nested structures this will mean you will use the same class to represent all layers:

> JSON.parse('{"a":1, "b":{ "a": 32 }}', object_class: MyClass)
=> #<MyClass:0x00007fb5110b2b38 @a=1, @b=#<MyClass:0x00007fb5110b2908 @a=32>>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRodView Question on Stackoverflow
Solution 1 - RubyGregView Answer on Stackoverflow
Solution 2 - Rubynevan kingView Answer on Stackoverflow
Solution 3 - Rubydav_iView Answer on Stackoverflow
Solution 4 - RubykeymoneView Answer on Stackoverflow
Solution 5 - Rubyguy mograbiView Answer on Stackoverflow
Solution 6 - RubyAdverblyView Answer on Stackoverflow
Solution 7 - RubydamianmrView Answer on Stackoverflow
Solution 8 - RubyErik MadsenView Answer on Stackoverflow