JSON Pointers (RFC 6901)
defines a string syntax for identifying a specific location within a JSON, or
similar, document. This crate provides two types, [Pointer] and [PointerBuf]
(akin to [Path] and [PathBuf]), for working with them abstractly.
A pointer is composed of zero or more [Token]s, single segments which
represent a field of an object or an [index] of an array, and are bounded by
either '/' or the end of the string. Tokens are lightly encoded, where '~'
is escaped as "~0" due to it signaling encoding and '/' is escaped as "~1"
because '/' separates tokens and would split the token into two otherwise.
[Token]s can be iterated over using either [Tokens], returned from the
[tokens] method of a pointer or [Components], returned from the
[components] method. The difference being that Tokens iterates over each
token in the pointer, while Components iterates over [Component]s, which can
represent the root of the document or a single token of the pointer.
Operations [resolve], [assign] and [delete] are provided as traits with
corresponding methods on pointer types. Implementations of each trait are
provided for value types of the crates [serde_json] and [toml]. All
operations are enabled by default but are gated by feature
flags.
To parse a [Pointer] from a string, use either [Pointer::parse], for
potentially fallible parsing, or the const fn from_static to produce a
&'static Pointer from a string that is known to be valid.
use jsonptr::Pointer;
let ptr = Pointer::parse("/examples/0/name").unwrap();
let static_ptr = Pointer::from_static("/examples/0/name");
assert_eq!(ptr, static_ptr);
assert_eq!(ptr.get(1..).unwrap(), Pointer::parse("/0/name").unwrap());
let parent = ptr.parent().unwrap();
assert_eq!(parent, Pointer::parse("/examples/0").unwrap());
let (token, remaining) = ptr.split_front().unwrap();
assert_eq!(token.decoded(), "examples");
assert_eq!(remaining, Pointer::parse("/0/name").unwrap());
[PointerBuf]s can be parsed using [PointerBuf::parse] or constructed from an
iterator of [Token]s with the [from_tokens] method:
use jsonptr::PointerBuf;
let mut buf = PointerBuf::parse("/examples/0/name").unwrap();
let from_tokens = PointerBuf::from_tokens(["examples", "0", "name"]);
assert_eq!(&buf, &from_tokens);
buf.push_front("pointer");
buf.push_front("~");
buf.push_back("/");
assert_eq!(buf.as_str(), "/~0/pointer/examples/0/name/~1");
Iterating over the tokens or components of a pointer:
use jsonptr::{Pointer, Component, Token};
let ptr = Pointer::from_static("/path/to/value");
// Using the `tokens` method:
let tokens: Vec<_> = ptr.tokens().collect();
assert_eq!(tokens, vec![Token::new("path"), Token::new("to"), Token::new("value")]);
// Using the `components` method:
let mut components = ptr.components();
assert_eq!(components.next(), Some(Component::Root));
assert_eq!(components.next(), Some(Component::Token(Token::new("path"))));
assert_eq!(components.next(), Some(Component::Token(Token::new("to"))));
assert_eq!(components.next(), Some(Component::Token(Token::new("value"))));
To get a value at the location of a pointer, use either the [Resolve] and
[ResolveMut] traits or [Pointer::resolve] and [Pointer::resolve_mut]
methods. See the [resolve] mod for more information.
use jsonptr::Pointer;
use serde_json::json;
let ptr = Pointer::parse("/foo/bar").unwrap();
let data = json!({"foo": { "bar": 34 }});
let bar = ptr.resolve(&data).unwrap();
assert_eq!(bar, &json!(34));
Values can be set, with path expansion, using the either the [Assign] trait or
[Pointer::assign]. See [assign] for more information.
use jsonptr::Pointer;
use serde_json::json;
let ptr = Pointer::parse("/secret/universe").unwrap();
let mut data = json!({"secret": { "universe": 42 }});
let replaced = ptr.assign(&mut data, json!(34)).unwrap();
assert_eq!(replaced, Some(json!(42)));
assert_eq!(data, json!({"secret": { "universe": 34 }}));
Values can be removed with the either the [Delete] trait or
[Pointer::delete]. See [delete] for more information.
use jsonptr::Pointer;
use serde_json::json;
let ptr = Pointer::parse("/secret/universe").unwrap();
let mut data = json!({"secret": { "universe": 42 }});
let replaced = ptr.assign(&mut data, json!(34)).unwrap();
assert_eq!(replaced, Some(json!(42)));
assert_eq!(data, json!({"secret": { "universe": 34 }}));
Any error produced by function calls into methods of traits or types of this
crate can be converted into a [Report] which contains the original error
and the [String] which failed to parse or the [PointerBuf] which failed to
resolve or assign.
use jsonptr::{Pointer, Diagnose};
let ptr_str = "foo/bar";
let err /* Result<&Pointer, Report<ParseError>> */ = Pointer::parse(ptr_str).diagnose(ptr_str).unwrap_err();
assert!(err.original().is_no_leading_slash());
In the case of [PointerBuf::parse], the [ParseError] is always wrapped in a
[Report] so that the input String is not dropped.
use jsonptr::{PointerBuf};
let ptr_str = "foo/bar";
let err /* Result<&PointerBuf, Report<ParseError>> */ = PointerBuf::parse(ptr_str).unwrap_err();
assert!(err.original().is_no_leading_slash());
| Flag | Description | Enables | Default |
|---|---|---|---|
"std" |
Implements std::error::Error for error types |
✓ | |
"serde" |
Enables [serde] support for types |
✓ | |
"json" |
Implements ops for [serde_json::Value] |
"serde" |
✓ |
"toml" |
Implements ops for [toml::Value] |
"std", toml |
|
"assign" |
Enables the [assign] module and related pointer methods, providing a means to assign a value to a specific location within a document |
✓ | |
"resolve" |
Enables the [resolve] module and related pointer methods, providing a means to resolve a value at a specific location within a document |
✓ | |
"delete" |
Enables the [delete] module and related pointer methods, providing a means to delete a value at a specific location within a document |
"resolve" |
✓ |
"miette" |
Enables integration with miette for error reporting |
"std" |
Licensed under either of
at your convenience.
Contributions and feedback are always welcome and appreciated. If you find an issue, please open a ticket or a pull request.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
$ claude mcp add jsonptr \
-- python -m otcore.mcp_server <graph>