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?
18 Answers
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:
2Just 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 5As 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.
It looks like a JSON string. You can use one of many JSON libraries and it's as simple as doing:
JSON.parse(string) 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.
2Don'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 ):
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.
I suggest Oj as it is waaaaaay faster than the standard JSON library.
(see performance comparisons here)
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>>