README.md in jsonpath-0.4.2 vs README.md in jsonpath-0.5.0

- old
+ new

@@ -1,62 +1,132 @@ -# Jsonpath +# JsonPath This is an implementation of http://goessner.net/articles/JsonPath/. +## What is JsonPath? + +JsonPath is a way of addressing elements within a JSON object. Similar to xpath of yore, JsonPath lets you +traverse a json object and manipulate or access it. + ## Usage +### Command-line + There is stand-alone usage through the binary `jsonpath` jsonpath [expression] (file|string) If you omit the second argument, it will read stdin, assuming one valid JSON object per line. Expression must be a valid jsonpath expression. -As well, you can include it as a library. +### Library +To use JsonPath as a library simply include and get goin'! + ~~~~~ {ruby} - object = JSON.parse(<<-HERE_DOC) - {"store": - {"bicycle": - {"price":19.95, "color":"red"}, - "book":[ - {"price":8.95, "category":"reference", "title":"Sayings of the Century", "author":"Nigel Rees"}, - {"price":12.99, "category":"fiction", "title":"Sword of Honour", "author":"Evelyn Waugh"}, - {"price":8.99, "category":"fiction", "isbn":"0-553-21311-3", "title":"Moby Dick", "author":"Herman Melville"}, - {"price":22.99, "category":"fiction", "isbn":"0-395-19395-8", "title":"The Lord of the Rings", "author":"J. R. R. Tolkien"} - ] - } - } - HERE_DOC +require 'jsonpath' - JsonPath.new('$..price').on(object) - # => [19.95, 8.95, 12.99, 8.99, 22.99] +json = <<-HERE_DOC +{"store": + {"bicycle": + {"price":19.95, "color":"red"}, + "book":[ + {"price":8.95, "category":"reference", "title":"Sayings of the Century", "author":"Nigel Rees"}, + {"price":12.99, "category":"fiction", "title":"Sword of Honour", "author":"Evelyn Waugh"}, + {"price":8.99, "category":"fiction", "isbn":"0-553-21311-3", "title":"Moby Dick", "author":"Herman Melville","color":"blue"}, + {"price":22.99, "category":"fiction", "isbn":"0-395-19395-8", "title":"The Lord of the Rings", "author":"Tolkien"} + ] + } +} +HERE_DOC +~~~~~ - JsonPath.on(object, '$..author') - # => ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"] +Now that we have a JSON object, let's get all the prices present in the object. We create an object for the path +in the following way. - JsonPath.new('$..book[::2]').on(object) - # => [{"price"=>8.95, "category"=>"reference", "author"=>"Nigel Rees", "title"=>"Sayings of the Century"}, {"price"=>8.99, "category"=>"fiction", "author"=>"Herman Melville", "title"=>"Moby Dick", "isbn"=>"0-553-21311-3"}] +~~~~~ {ruby} +path = JsonPath.new('$..price') +~~~~~ - JsonPath.new('$..color').first(object) - # => "red" +Now that we have a path, let's apply it to the object above. - # Lazy enumeration - only needs to find the first two matches - JsonPath.new('$..price').enum_on(object).each do |match| - break price if price < 15.0 - end - # => 8.95 +~~~~~ {ruby} +path.on(json) +# => [19.95, 8.95, 12.99, 8.99, 22.99] ~~~~~ +Or on some other object ... + +~~~~~ {ruby} +path.on('{"books":[{"title":"A Tale of Two Somethings","price":18.88}]}') +# => [18.88] +~~~~~ + +You can also just combine this into one mega-call with the convenient `JsonPath.on` method. + +~~~~~ {ruby} +JsonPath.on(json, '$..author') +# => ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "Tolkien"] +~~~~~ + +Of course the full JsonPath syntax is supported, such as array slices + +~~~~~ {ruby} +JsonPath.new('$..book[::2]').on(json) +# => [ +# {"price"=>8.95, "category"=>"reference", "author"=>"Nigel Rees", "title"=>"Sayings of the Century"}, +# {"price"=>8.99, "category"=>"fiction", "author"=>"Herman Melville", "title"=>"Moby Dick", "isbn"=>"0-553-21311-3"} +# ] +~~~~~ + +...and evals. + +~~~~~ {ruby} +JsonPath.new('$..price[?(@ < 20)]').on(json) +# => [8.95, 8.99] +~~~~~ + +There is a convenience method, `#first` that gives you the first element for a JSON object and path. + +~~~~~ {ruby} +JsonPath.new('$..color').first(object) +# => "red" +~~~~~ + +As well, we can directly create an `Enumerable` at any time using `#[]`. + +~~~~~ {ruby} +enum = JsonPath.new('$..color')[object] +# => #<JsonPath::Enumerable:...> +enum.first +# => "red" +enum.any?{ |c| c == 'red' } +# => true +~~~~~ + You can optionally prevent eval from being called on sub-expressions by passing in :allow_eval => false to the constructor. -If you'd like to do substitution in a json object, do this: +### Manipulation +If you'd like to do substitution in a json object, you can use `#gsub` or `#gsub!` to modify the object in place. + ~~~~~ {ruby} - JsonPath.for({'test' => 'time'}).gsub('$..test') {|v| v << v} +JsonPath.for('{"candy":"lollipop"}').gsub('$..candy') {|v| "big turks" }.to_hash ~~~~~ The result will be ~~~~~ {ruby} - {'test' => 'timetime'} +{'candy' => 'big turks'} +~~~~~ + +If you'd like to remove all nil keys, you can use `#compact` and `#compact!`. To remove all keys under a certain path, use `#delete` or `#delete!`. You can even chain these methods together as follows: + +~~~~~ {ruby} +json = '{"candy":"lollipop","noncandy":null,"other":"things"}' +o = JsonPath.for(json). + gsub('$..candy') {|v| "big turks" }. + compact. + delete('$..other'). + to_hash +# => {"candy" => "big turks"} ~~~~~