430

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?

1
  • 27
    JSON is directly supported in Ruby, and has been since at least Ruby v1.9.3, so there is no need to install a gem unless you're using something older. Simply use require 'json' in your code. Commented Nov 9, 2015 at 17:41

8 Answers 8

646

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:

Sign up to request clarification or add additional context in comments.

2 Comments

Also you can sets the option symbolize_names to true, in order to get keys as symbols. Exemple: JSON.parse(string, symbolize_names: true) #=> {key: :value}
JSON is directly supported in Ruby, and has been since at least Ruby v1.9.3, so there is no need to install a gem unless you're using something older. Simply use require 'json' in your code.
240

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

5 Comments

Important note: '{ "a": "bob" }' is valid. "{ 'a': 'bob' }" is not.
@LinusAn because JSON requires double quotes around strings. See string in the JSON definition ( json.org ): "A string is a sequence of zero or more Unicode characters, wrapped in double quotes, using backslash escapes."
In many cases you want to wrap JSON.parse within a rescue block for JSON::ParserError.
JSON.parse("[#{value}]")[0] to avoid the error A JSON text must at least contain two octets!
Can you make your answer complete by including a sample example data from shops.json?
42

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.

Comments

18

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

JSON.parse(string)

Comments

10

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.

Comments

7

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.

3 Comments

Yes, JSON is actually parsed by the Psych code, which also parses YAML in Ruby. And JSON parsing was introduced in Ruby v1.9.3.
The reason this works is that semantically (most) JSON is valid YAML (particularly YAML 1.2)
I get "undefined method `load_file' for JSON:Module" on ruby 2.3.8
4

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

https://github.com/ohler55/oj

(see performance comparisons here)

Comments

3

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>>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.