philiprehberger-json_path

Tests Gem Version Last updated

JSONPath expression evaluator with dot notation, wildcards, slices, filters, and recursive descent

Requirements

  • Ruby >= 3.1

Installation

Add to your Gemfile:

gem "philiprehberger-json_path"

Or install directly:

gem install philiprehberger-json_path

Usage

require "philiprehberger/json_path"

data = {
  'store' => {
    'books' => [
      { 'title' => 'Ruby', 'price' => 30 },
      { 'title' => 'Python', 'price' => 25 },
      { 'title' => 'Go', 'price' => 20 }
    ]
  }
}

Philiprehberger::JsonPath.query(data, '$.store.books[*].title')
# => ["Ruby", "Python", "Go"]

Philiprehberger::JsonPath.values(data, '$.store.books[*].title')
# => ["Ruby", "Python", "Go"]  (alias for query)

Philiprehberger::JsonPath.first(data, '$.store.books[0].title')
# => "Ruby"

Philiprehberger::JsonPath.count(data, '$.store.books[*]')
# => 3

Philiprehberger::JsonPath.exists?(data, '$.store.books')
# => true

Matched paths

Use paths to get canonical JSONPath strings for every match, rather than the values themselves. Each returned path re-evaluates back to the single element it identifies, making it handy for diffing, patching, or reporting.

Philiprehberger::JsonPath.paths(data, '$.store.books[*].title')
# => ["$.store.books[0].title", "$.store.books[1].title", "$.store.books[2].title"]

Philiprehberger::JsonPath.paths(data, '$.store.books[?(@.price>22)]')
# => ["$.store.books[0]", "$.store.books[1]"]

Philiprehberger::JsonPath.paths(data, '$.missing')
# => []

Recursive Descent

Philiprehberger::JsonPath.query(data, '$..price')
# => [30, 25, 20]

Philiprehberger::JsonPath.query(data, '$..title')
# => ["Ruby", "Python", "Go"]

Array Indexing and Slicing

Philiprehberger::JsonPath.query(data, '$.store.books[0]')
# => [{"title"=>"Ruby", "price"=>30}]

Philiprehberger::JsonPath.query(data, '$.store.books[-1].title')
# => ["Go"]

Philiprehberger::JsonPath.query(data, '$.store.books[0:2].title')
# => ["Ruby", "Python"]

Filter Expressions

Philiprehberger::JsonPath.query(data, '$.store.books[?(@.price>22)].title')
# => ["Ruby", "Python"]

Philiprehberger::JsonPath.query(data, "$.store.books[?(@.title=='Go')].price")
# => [20]

Negation Filters

data = { 'items' => [{ 'name' => 'a', 'hidden' => true }, { 'name' => 'b' }] }

Philiprehberger::JsonPath.query(data, '$.items[?(!@.hidden)].name')
# => ["b"]

Length Comparisons

data = {
  'groups' => [
    { 'name' => 'team1', 'members' => ['Alice', 'Bob'] },
    { 'name' => 'team2', 'members' => [] }
  ]
}

Philiprehberger::JsonPath.query(data, '$.groups[?(@.members.length > 0)].name')
# => ["team1"]

Supported Syntax

Syntax Description
$ Root element
.key Dot notation for object keys
['key'] Bracket notation for object keys
[n] Array index (supports negative)
[*] Wildcard (all elements)
[start:end] Array slice
..key Recursive descent (match key at any depth)
[?(@.key>val)] Filter expression
[?(@.key)] Existence filter
[?(!@.key)] Negation filter
[?(@.key.length>n)] Length comparison filter

API

Method Description
JsonPath.query(data, path) Return all matches as an array
JsonPath.values(data, path) Alias for query
JsonPath.first(data, path) Return the first match or nil
JsonPath.count(data, path) Return the number of matches
JsonPath.exists?(data, path) Check if any match exists
JsonPath.paths(data, path) Return canonical JSONPath strings for each match

Development

bundle install
bundle exec rspec
bundle exec rubocop

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT