Hi,
Sometimes while reading JSON files I find using JSON::Serializable
very verbose depending on the JSON structure. So I would like a dig
like method to just go to the deeps of the nested JSON objects and get what I want but trying to allocate not much memory like JSON.parse
.
A dummy example: reading this JSON where I want the value of the !
key, i.e. 42:
{"hey": { "ho": { "!": 42 } } }
I would like something like:
input = %({"hey": { "ho": { "!": 42 } } })
parser = JSON::PullParser.new(input)
parser.on_key("hey", "ho", "!") do
puts parser.read_int
end
Instead of writing a lot of nested classes that implement JSON::Serializable
or writting a lot of nested blocks using JSON::PullParser
just to deal with a verbose JSON structure.
A monkey patch that make the code above work is show bellow
require "json"
class JSON::PullParser
private def on_key(keys : Indexable, idx : Int32, &block : self -> _)
key = keys[idx]
on_key(key) do
if idx == keys.size - 1
block.call(self)
else
on_key(keys, idx + 1, &block)
end
end
end
def on_key(*keys, &block : self -> _)
on_key(keys, 0, &block)
end
end
The code above only works with nested JSON objects, maybe adding support to arrays would be nice too, i.e. if the key is a number the code assumes the user is expecting an array and interpret the number as the array index, since JSON keys are always strings by definition…
Anyway… I find this useful for me, is it useful enough to deserve my time crafting a PR to add this to stdlib?
P.S.: I come to this trying to read the JSON output of an Elastic Search reply using JSON.parse
and failing due to Int128 numbers in the JSON… so I had to use JSON::PullParser
.