Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?


Failed to load latest commit information.
Latest commit message
Commit time


This is an implementation of

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.



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.


To use JsonPath as a library simply include and get goin'!

require 'jsonpath'

json = <<-HERE_DOC
    {"price":19.95, "color":"red"},
      {"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"}

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.

path ='$..price')

Now that we have a path, let's apply it to the object above.

# => [19.95, 8.95, 12.99, 8.99, 22.99]

Or reuse it later on some other object (thread safe) ...

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.

JsonPath.on(json, '$')
# => ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "Tolkien"]

Of course the full JsonPath syntax is supported, such as array slices'$[::2]').on(json)
# => [
#      {"price" => 8.95, "category" => "reference", "title" => "Sayings of the Century", "author" => "Nigel Rees"},
#      {"price" => 8.99, "category" => "fiction", "isbn" => "0-553-21311-3", "title" => "Moby Dick", "author" => "Herman Melville","color" => "blue"},
#    ]

...and evals, including those with conditional operators"$..price[?(@ < 10)]").on(json)
# => [8.95, 8.99]"$[?(@['price'] == 8.95 || @['price'] == 8.99)].title").on(json)
# => ["Sayings of the Century", "Moby Dick"]"$[?(@['price'] == 8.95 && @['price'] == 8.99)].title").on(json)
# => []

There is a convenience method, #first that gives you the first element for a JSON object and path.'$..color').first(json)
# => "red"

As well, we can directly create an Enumerable at any time using #[].

enum ='$..color')[json]
# => #<JsonPath::Enumerable:...>
# => "red"
enum.any?{ |c| c == 'red' }
# => true

For more usage examples and variations on paths, please visit the tests. There are some more complex ones as well.

Querying ruby data structures

If you have ruby hashes with symbolized keys as input, you can use :use_symbols to make JsonPath work fine on them too:

book = { title: "Sayings of the Century" }'$.title').on(book)
# => []'$.title', use_symbols: true).on(book)
# => ["Sayings of the Century"]

JsonPath also recognizes objects responding to dig (introduced in ruby 2.3), and therefore works out of the box with Struct, OpenStruct, and other Hash-like structures:

book_class =
book ="Sayings of the Century")'$.title').on(book)
# => ["Sayings of the Century"]

JsonPath is able to query pure ruby objects and uses __send__ on them. The option is enabled by default in JsonPath 1.x, but we encourage to enable it explicitly:

book_class ={ attr_accessor :title }
book =
book.title = "Sayings of the Century"'$.title', allow_send: true).on(book)
# => ["Sayings of the Century"]

Other available options

By default, JsonPath does not return null values on unexisting paths. This can be changed using the :default_path_leaf_to_null option'$[*].isbn').on(json)
# => ["0-553-21311-3", "0-395-19395-8"]'$[*].isbn', default_path_leaf_to_null: true).on(json)
# => [nil, nil, "0-553-21311-3", "0-395-19395-8"]

When JsonPath returns a Hash, you can ask to symbolize its keys using the :symbolize_keys option'$[0]').on(json)
# => [{"category" => "reference", ...}]'$[0]', symbolize_keys: true).on(json)
# => [{category: "reference", ...}]

Selecting Values

It's possible to select results once a query has been defined after the query. For example given this JSON data:

    "store": {
        "book": [
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99

... and this query:


... the result can be filtered as such:

      "category" : "reference",
      "author" : "Nigel Rees"
      "category" : "fiction",
      "author" : "Evelyn Waugh"


If you'd like to do substitution in a json object, you can use #gsub or #gsub! to modify the object in place.

JsonPath.for('{"candy":"lollipop"}').gsub('$..candy') {|v| "big turks" }.to_hash

The result will be

{'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:

json = '{"candy":"lollipop","noncandy":null,"other":"things"}'
o = JsonPath.for(json).
  gsub('$..candy') {|v| "big turks" }.
# => {"candy" => "big turks"}

Fetch all paths

To fetch all possible paths in given json, you can use fetch_all_paths method.


    "store": {
        "book": [
                "category": "reference",
                "author": "Nigel Rees"
                "category": "fiction",
                "author": "Evelyn Waugh"

... and this query:


... the result will be:

["$", "$.store", "$", "$[0].category", "$[0].author", "$[0]", "$[1].category", "$[1].author", "$[1]"]


Please feel free to submit an Issue or a Pull Request any time you feel like you would like to contribute. Thank you!

Running an individual test

ruby -Ilib:../lib test/test_jsonpath.rb --name test_wildcard_on_intermediary_element_v6