#json-query #json

jmespath

Rust implementation of JMESPath, a query language for JSON

5 releases (3 breaking)

0.3.0 Feb 24, 2022
0.2.0 Aug 26, 2017
0.1.1 Jan 8, 2017
0.1.0 Dec 16, 2016
0.0.1 Jan 31, 2016

#607 in Encoding

Download history 15660/week @ 2024-06-15 18768/week @ 2024-06-22 15154/week @ 2024-06-29 9912/week @ 2024-07-06 8959/week @ 2024-07-13 9806/week @ 2024-07-20 8765/week @ 2024-07-27 6956/week @ 2024-08-03 7313/week @ 2024-08-10 9570/week @ 2024-08-17 8167/week @ 2024-08-24 9202/week @ 2024-08-31 8266/week @ 2024-09-07 5333/week @ 2024-09-14 8933/week @ 2024-09-21 6307/week @ 2024-09-28

30,567 downloads per month
Used in 15 crates (8 directly)

MIT license

165KB
4K SLoC

Rust implementation of JMESPath, a query language for JSON.

Compiling JMESPath expressions

Use the jmespath::compile function to compile JMESPath expressions into reusable Expression structs. The Expression struct can be used multiple times on different values without having to recompile the expression.

use jmespath;

let expr = jmespath::compile("foo.bar | baz").unwrap();

// Parse some JSON data into a JMESPath variable
let json_str = "{\"foo\":{\"bar\":{\"baz\":true}}}";
let data = jmespath::Variable::from_json(json_str).unwrap();

// Search the data with the compiled expression
let result = expr.search(data).unwrap();
assert_eq!(true, result.as_boolean().unwrap());

You can get the original expression as a string and the parsed expression AST from the Expression struct:

use jmespath;
use jmespath::ast::Ast;

let expr = jmespath::compile("foo").unwrap();
assert_eq!("foo", expr.as_str());
assert_eq!(&Ast::Field {name: "foo".to_string(), offset: 0}, expr.as_ast());

JMESPath variables

In order to evaluate expressions against a known data type, the jmespath::Variable enum is used as both the input and output type. More specifically, Rcvar (or jmespath::Rcvar) is used to allow shared, reference counted data to be used by the JMESPath interpreter at runtime.

By default, Rcvar is an std::rc::Rc<Variable>. However, by specifying the sync feature, you can utilize an std::sync::Arc<Variable> to share Expression structs across threads.

Any type that implements jmespath::ToJmespath can be used in a JMESPath Expression. Various types have default ToJmespath implementations, including serde::ser::Serialize. Because jmespath::Variable implements serde::ser::Serialize, many existing types can be searched without needing an explicit coercion, and any type that needs coercion can be implemented using serde's macros or code generation capabilities. This includes a number of common types, including serde's serde_json::Value enum.

The return value of searching data with JMESPath is also an Rcvar. Variable has a number of helper methods that make it a data type that can be used directly, or you can convert Variable to any serde value implementing serde::de::Deserialize.

Custom Functions

You can register custom functions with a JMESPath expression by using a custom Runtime. When you call jmespath::compile, you are using a shared Runtime instance that is created lazily using lazy_static. This shared Runtime utilizes all of the builtin JMESPath functions by default. However, custom functions may be utilized by creating a custom Runtime and compiling expressions directly from the Runtime.

use jmespath::{Runtime, Context, Rcvar};
use jmespath::functions::{CustomFunction, Signature, ArgumentType};

// Create a new Runtime and register the builtin JMESPath functions.
let mut runtime = Runtime::new();
runtime.register_builtin_functions();

// Create an identity string function that returns string values as-is.
runtime.register_function("str_identity", Box::new(CustomFunction::new(
    Signature::new(vec![ArgumentType::String], None),
    Box::new(|args: &[Rcvar], _: &mut Context| Ok(args[0].clone()))
)));

// You can also use normal closures as functions.
runtime.register_function("identity",
    Box::new(|args: &[Rcvar], _: &mut Context| Ok(args[0].clone())));

let expr = runtime.compile("str_identity('foo')").unwrap();
assert_eq!("foo", expr.search(()).unwrap().as_string().unwrap());

let expr = runtime.compile("identity('bar')").unwrap();
assert_eq!("bar", expr.search(()).unwrap().as_string().unwrap());

Dependencies

~0.5–1MB
~20K SLoC