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