diff --git a/README.md b/README.md index 32cb162..46dffb7 100644 --- a/README.md +++ b/README.md @@ -253,6 +253,42 @@ o = JsonPath.for(json). # => {"candy" => "big turks"} ``` +### Fetch all paths + +To fetch all possible paths in given json, you can use `fetch_all_paths` method. + +data: + +```bash +{ + "store": { + "book": [ + { + "category": "reference", + "author": "Nigel Rees" + }, + { + "category": "fiction", + "author": "Evelyn Waugh" + } + ] +} +``` + +... and this query: + +```ruby +JsonPath.fetch_all_path(data) +``` + +... the result will be: + +```bash +["$", "$.store", "$.store.book", "$.store.book[0].category", "$.store.book[0].author", "$.store.book[0]", "$.store.book[1].category", "$.store.book[1].author", "$.store.book[1]"] +``` + + + # Contributions Please feel free to submit an Issue or a Pull Request any time you feel like diff --git a/jsonpath.gemspec b/jsonpath.gemspec index 0158718..eb21f8f 100644 --- a/jsonpath.gemspec +++ b/jsonpath.gemspec @@ -23,5 +23,6 @@ Gem::Specification.new do |s| s.add_development_dependency 'code_stats' s.add_development_dependency 'minitest', '~> 2.2.0' s.add_development_dependency 'phocus' + s.add_development_dependency 'racc' s.add_development_dependency 'rake' end diff --git a/lib/jsonpath.rb b/lib/jsonpath.rb index e976d4b..e4d7a59 100644 --- a/lib/jsonpath.rb +++ b/lib/jsonpath.rb @@ -86,6 +86,39 @@ def on(obj_or_str, opts = {}) end a end + + def self.fetch_all_path(obj) + all_paths = ['$'] + find_path(obj, '$', all_paths, obj.class == Array) + return all_paths + end + + def self.find_path(obj, root_key, all_paths, is_array = false) + obj.each do |key, value| + table_params = { key: key, root_key: root_key} + is_loop = value.class == Array || value.class == Hash + if is_loop + path_exp = construct_path(table_params) + all_paths << path_exp + find_path(value, path_exp, all_paths, value.class == Array) + elsif is_array + table_params[:index] = obj.find_index(key) + path_exp = construct_path(table_params) + find_path(key, path_exp, all_paths, key.class == Array) if key.class == Hash || key.class == Array + all_paths << path_exp + else + all_paths << construct_path(table_params) + end + end + end + + def self.construct_path(table_row) + if table_row[:index] + return table_row[:root_key] + '['+ table_row[:index].to_s + ']' + else + return table_row[:root_key] + '.'+ table_row[:key] + end + end def first(obj_or_str, *args) enum_on(obj_or_str).first(*args) diff --git a/test/test_jsonpath.rb b/test/test_jsonpath.rb index 849e976..b977bde 100644 --- a/test/test_jsonpath.rb +++ b/test/test_jsonpath.rb @@ -1152,4 +1152,19 @@ def example_object '_links' => { 'self' => {} } } } end + + def test_fetch_all_path + data = { + "foo" => nil, + "bar" => { + "baz" => nil + }, + "bars" => [ + { "foo" => 12 }, + { "foo" => nil }, + { } + ] + } + assert_equal ["$", "$.foo", "$.bar", "$.bar.baz", "$.bars", "$.bars[0].foo", "$.bars[0]", "$.bars[1].foo", "$.bars[1]", "$.bars[2]"], JsonPath.fetch_all_path(data) + end end