Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

JSONPath, JSON Patch and JSON Pointer for Ruby

License

NotificationsYou must be signed in to change notification settings

jg-rp/ruby-json-p3

Repository files navigation

We followRFC 9535 strictly and test against theJSONPath Compliance Test Suite.

LicenseTests
Gem VersionStatic Badge


Table of Contents

Install

Add'json_p3' to your Gemfile:

gem 'json_p3', '~> 0.4.1'

Or

gem install json_p3

Checksum

JSON P3 is cryptographically signed. To be sure the gem you install hasn't been tampered with, add my public key (if you haven't already) as a trusted certificate:

gem cert --add <(curl -Ls https://raw.githubusercontent.com/jg-rp/ruby-json-p3/refs/heads/main/certs/jgrp.pem)

Followed by:

gem install json_p3 -P MediumSecurity

JSON P3 has no runtime dependencies, so-P HighSecurity is OK too. Seehttps://guides.rubygems.org/security/ for more information.

Example

require"json_p3"require"json"data=JSON.parse<<~JSON  {    "users": [      {        "name": "Sue",        "score": 100      },      {        "name": "Sally",        "score": 84,        "admin": false      },      {        "name": "John",        "score": 86,        "admin": true      },      {        "name": "Jane",        "score": 55      }    ],    "moderator": "John"  }JSONJSONP3.find("$.users[?@.score > 85]",data).eachdo |node|putsnode.valueend# {"name"=>"Sue", "score"=>100}# {"name"=>"John", "score"=>86, "admin"=>true}

Or, reading JSON data from a file:

require"json_p3"require"json"data=JSON.load_file("/path/to/some.json")JSONP3.find("$.some.query",data).eachdo |node|putsnode.valueend

You could read data from a YAML formatted file too, or any data format that can be loaded into hashes and arrays.

require"json_p3"require"yaml"data=YAML.load_file("/tmp/some.yaml")JSONP3.find("$.users[?@.score > 85]",data).eachdo |node|putsnode.valueend

Links

Related projects

  • Python JSONPath RFC 9535 - A Python implementation of JSONPath that follows RFC 9535 strictly.
  • Python JSONPath - Another Python package implementing JSONPath, but with additional features and customization options.
  • JSON P3 - RFC 9535 implemented in TypeScript.

Quick start

find

find(query, value) -> Array<JSONPathNode>

Apply JSONPath expressionquery to JSON-like datavalue. An array of JSONPathNode instances is returned, one node for each value matched byquery. The returned array will be empty if there were no matches.

EachJSONPathNode has:

  • avalue attribute, which is the JSON-like value associated with the node.
  • alocation attribute, which is a nested array of hash/object names and array indices that were required to reach the node's value in the target JSON document.
  • apath() method, which returns the normalized path to the node in the target JSON document.
require"json_p3"require"json"data=JSON.parse<<~JSON  {    "users": [      {        "name": "Sue",        "score": 100      },      {        "name": "Sally",        "score": 84,        "admin": false      },      {        "name": "John",        "score": 86,        "admin": true      },      {        "name": "Jane",        "score": 55      }    ],    "moderator": "John"  }JSONJSONP3.find("$.users[?@.score > 85]",data).eachdo |node|puts"#{node.value} at#{node.path}"end# {"name"=>"Sue", "score"=>100} at $['users'][0]# {"name"=>"John", "score"=>86, "admin"=>true} at $['users'][2]

find_enum

find_enum(query, value) -> Enumerable<JSONPathNode>

find_enum is an alternative tofind which returns an enumerable (usually an enumerator) ofJSONPathNode instances instead of an array. Depending on the query and the data the query is applied to,find_enum can be more efficient thanfind, especially for large data and queries using recursive descent segments.

# ... continued from aboveJSONP3.find_enum("$.users[?@.score > 85]",data).eachdo |node|puts"#{node.value} at#{node.path}"end# {"name"=>"Sue", "score"=>100} at $['users'][0]# {"name"=>"John", "score"=>86, "admin"=>true} at $['users'][2]

compile

compile(query) -> JSONPath

Prepare a JSONPath expression for repeated application to different JSON-like data. An instance ofJSONPath has afind(data) method, which behaves similarly to the module-levelfind(query, data) method.

require"json_p3"require"json"data=JSON.parse<<~JSON  {    "users": [      {        "name": "Sue",        "score": 100      },      {        "name": "Sally",        "score": 84,        "admin": false      },      {        "name": "John",        "score": 86,        "admin": true      },      {        "name": "Jane",        "score": 55      }    ],    "moderator": "John"  }JSONpath=JSONP3.compile("$.users[?@.score > 85]")path.find(data).eachdo |node|puts"#{node.value} at#{node.path}"end# {"name"=>"Sue", "score"=>100} at $['users'][0]# {"name"=>"John", "score"=>86, "admin"=>true} at $['users'][2]

match / first

match(query, value) -> JSONPathNode | nil

match (aliasfirst) returns a node for the first available match when applyingquery tovalue, ornil if there were no matches.

match?

match?(query, value) -> bool

match? returnstrue if there was at least one match from applyingquery tovalue, orfalse otherwise.

JSONPathEnvironment

Thefind,find_enum andcompile methods described above are convenience methods equivalent to:

JSONP3::DEFAULT_ENVIRONMENT.find(query, data)
JSONP3::DEFAULT_ENVIRONMENT.find_enum(query, data)

and

JSONP3::DEFAULT_ENVIRONMENT.compile(query)

You could create your own environment like this:

require"json_p3"jsonpath=JSONP3::JSONPathEnvironment.newnodes=jsonpath.find("$.*",{"a"=>"b","c"=>"d"})ppnodes.map(&:value)# ["b", "d"]

To configure an environment with custom filter functions or non-standard selectors, inherit fromJSONPathEnvironment and override some of its constants or the#setup_function_extensions method.

classMyJSONPathEnvironment <JSONP3::JSONPathEnvironment# The maximum integer allowed when selecting array items by index.MAX_INT_INDEX=(2**53) -1# The minimum integer allowed when selecting array items by index.MIN_INT_INDEX= -(2**53) +1# The maximum number of arrays and hashes the recursive descent segment will# traverse before raising a {JSONPathRecursionError}.MAX_RECURSION_DEPTH=100# One of the available implementations of the _name selector_.## - {NameSelector} (the default) will select values from hashes using string keys.# - {SymbolNameSelector} will select values from hashes using string or symbol keys.## Implement your own name selector by inheriting from {NameSelector} and overriding# `#resolve`.NAME_SELECTOR=NameSelector# An implementation of the _index selector_. The default implementation will# select values from arrays only. Implement your own by inheriting from# {IndexSelector} and overriding `#resolve`.INDEX_SELECTOR=IndexSelector# Override this function to configure JSONPath function extensions.# By default, only the standard functions described in RFC 9535 are enabled.defsetup_function_extensions@function_extensions["length"]=Length.new@function_extensions["count"]=Count.new@function_extensions["value"]=Value.new@function_extensions["match"]=Match.new@function_extensions["search"]=Search.newend

JSONPathError

JSONPathError is the base class for all JSONPath exceptions. The following classes inherit fromJSONPathError and will only occur when parsing a JSONPath expression, not when applying a path to some data.

  • JSONPathSyntaxError
  • JSONPathTypeError
  • JSONPathNameError

JSONPathError implements#detailed_message. With recent versions of Ruby you should get useful error messages.

JSONP3::JSONPathSyntaxError: unexpected trailing whitespace  -> '$.foo ' 1:5  |1 | $.foo  |      ^ unexpected trailing whitespace

resolve

resolve(pointer, value) -> Object

Resolve a JSON Pointer (RFC 6901) against some data usingJSONP3.resolve().

require"json_p3"require"json"data=JSON.parse<<~JSON  {    "users": [      {        "name": "Sue",        "score": 100      },      {        "name": "Sally",        "score": 84,        "admin": false      },      {        "name": "John",        "score": 86,        "admin": true      },      {        "name": "Jane",        "score": 55      }    ],    "moderator": "John"  }JSONputsJSONP3.resolve("/users/1",data)# {"name"=>"Sally", "score"=>84, "admin"=>false}

If a pointer can not be resolved,JSONP3::JSONPointer::UNDEFINED is returned instead. You can use your own default value using thedefault: keyword argument.

# continued from aboveppJSONP3.resolve("/no/such/thing",data,default:nil)# nil

apply

apply(ops, value) -> Object

Apply a JSON Patch (RFC 6902) withJSONP3.apply().Data is modified in place.

require"json"require"json_p3"ops=<<~JSON  [    { "op": "add", "path": "/some/foo", "value": { "foo": {} } },    { "op": "add", "path": "/some/foo", "value": { "bar": [] } },    { "op": "copy", "from": "/some/other", "path": "/some/foo/else" },    { "op": "add", "path": "/some/foo/bar/-", "value": 1 }  ]JSONdata={"some"=>{"other"=>"thing"}}JSONP3.apply(JSON.parse(ops),data)ppdata# {"some"=>{"other"=>"thing", "foo"=>{"bar"=>[1], "else"=>"thing"}}}

JSONP3.apply(ops, value) is a convenience method equivalent toJSONP3::JSONPatch.new(ops).apply(value). Use theJSONPatch constructor when you need to apply the same patch to different data.

As well as passing an array of hashes following RFC 6902 as ops toJSONPatch, we offer a builder API to construct JSON Patch documents programmatically.

require"json_p3"data={"some"=>{"other"=>"thing"}}patch=JSONP3::JSONPatch.new.add("/some/foo",{"foo"=>[]}).add("/some/foo",{"bar"=>[]}).copy("/some/other","/some/foo/else").copy("/some/foo/else","/some/foo/bar/-")patch.apply(data)ppdata# {"some"=>{"other"=>"thing", "foo"=>{"bar"=>["thing"], "else"=>"thing"}}}

Contributing

Your contributions and questions are always welcome. Feel free to ask questions, report bugs or request features on theissue tracker or onGithub Discussions. Pull requests are welcome too.

Development

TheJSONPath Compliance Test Suite is included as a gitsubmodule. Clone the JSON P3 git repository and initialize the CTS submodule.

$ git clone git@github.com:jg-rp/ruby-json-p3.git$cd ruby-json-p3$ git submodule update --init

We useBundler andRake. Install development dependencies with:

bundle install

Run tests with:

bundle exec rake test

Lint with:

bundle exec rubocop

And type check with:

bundle exec steep

Run one of the benchmarks with:

bundle exec ruby performance/benchmark_ips.rb

Profiling

CPU profile

Dump profile data withbundle exec ruby performance/profile.rb, then generate an HTML flame graph with:

bundle exec stackprof --d3-flamegraph .stackprof-cpu-just-compile.dump > flamegraph-cpu-just-compile.html

Memory profile

Print memory usage to the terminal.

bundle exec ruby performance/memory_profile.rb

Notes to self

Build

bundle exec rake release andbundle exec rake build will look forgem-private_key.pem andgem-public_cert.pem in~/.gem.

TruffleRuby

On macOS Sonoma using MacPorts andrbenv,LIBYAML_PREFIX=/opt/local/lib is needed to install TruffleRuby and when executing anybundle command.

About

JSONPath, JSON Patch and JSON Pointer for Ruby

Topics

Resources

License

Stars

Watchers

Forks

Contributors2

  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp