# jsonpath-lib [![Build Status](https://travis-ci.org/freestrings/jsonpath.svg?branch=master)](https://travis-ci.org/freestrings/jsonpath) [![version](https://img.shields.io/crates/v/:jsonpath.svg)](https://crates.io/crates/jsonpath_lib) `Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. Rust 구현과 동일한 기능을 `Webassembly` 로 제공하는 것도 목표. The `Rust` version is a [JsonPath](https://goessner.net/articles/JsonPath/) implementation. It is also aimed to provide the same functionality as `Webassembly` in Rust implementation. ## 왜? To enjoy Rust! ## 목차 [With Javascript (Webassembly)](#with-javascript-webassembly) - [jsonpath-wasm library](#jsonpath-wasm-library) - [javascript - jsonpath.read(json: string|object, jsonpath: string)](#javascript---jsonpathreadjson-stringobject-jsonpath-string) - [javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string) - [javascript - jsonpath.reader(json: string|object)](#javascript---jsonpathreaderjson-stringobject) - [javascript - examples](#javascript---examples) [With Rust (as library)](#with-rust-as-library) - [jsonpath_lib library](#jsonpath_lib-library) - [rust - jsonpath::read(json: serde_json::value::Value, jsonpath: &str)](#rust---jsonpathreadjson-serde_jsonvaluevalue-jsonpath-str) - [rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str) - [rust - jsonpath::reader(json: serde_json::value::Value)](#rust---jsonpathreaderjson-serde_jsonvaluevalue) - [rust - examples](#rust---examples) [With AWS API Gateway](#with-aws-api-gateway) [Simple time check](#simple-time-check-with-dchesterjsonpath) ## With Javascript (WebAssembly) ### jsonpath-wasm library *(not yet published `jsonpath-wasm`)* ```javascript // browser import * as jsonpath from "jsonpath-wasm"; // nodejs let jsonpath = require('jsonpath-wasm'); ``` ### javascript - jsonpath.read(json: string|object, jsonpath: string) ```javascript let jsonObj = { "school": { "friends": [{"id": 0}, {"id": 1}] }, "friends": [{"id": 0}, {"id": 1}] }; let ret = [{"id": 0}, {"id": 0}]; let a = jsonpath.read(JSON.stringify(jsonObj), "$..friends[0]"); let b = jsonpath.read(jsonObj, "$..friends[0]"); console.log( JSON.stringify(ret) == JSON.stringify(a), JSON.stringify(a) == JSON.stringify(b) ); ``` ### javascript - jsonpath.compile(jsonpath: string) ```javascript let template = jsonpath.compile("$..friends[0]"); let jsonObj = { "school": { "friends": [ {"id": 0}, {"id": 1} ] }, "friends": [ {"id": 0}, {"id": 1} ] }; let ret = JSON.stringify([ {"id": 0}, {"id": 0} ]); // 1. read as json object console.log(JSON.stringify(template(jsonObj)) == ret); // 2. read as json string console.log(JSON.stringify(template(JSON.stringify(jsonObj))) == ret); let jsonObj2 = { "school": { "friends": [ {"name": "Millicent Norman"}, {"name": "Vincent Cannon"} ] }, "friends": [ {"id": 0}, {"id": 1} ] }; let ret2 = JSON.stringify([ {"id": 0}, {"name": "Millicent Norman"} ]); // 1. read as json object console.log(JSON.stringify(template(jsonObj2)) == ret2); // 2. read as json string console.log(JSON.stringify(template(JSON.stringify(jsonObj2))) == ret2); ``` ### javascript - jsonpath.reader(json: string|object) ```javascript let jsonObj = { "school": { "friends": [{"id": 0}, {"id": 1}] }, "friends": [{"id": 0},{"id": 1}] }; let ret1 = JSON.stringify([ {"id": 0}, {"id": 0} ]); let ret2 = JSON.stringify([ {"id": 1}, {"id": 1} ]); // 1. read as json object let reader = jsonpath.reader(jsonObj); console.log(JSON.stringify(reader("$..friends[0]")) == ret1); console.log(JSON.stringify(reader("$..friends[1]")) == ret2); // 2. read as json string let reader2 = jsonpath.reader(JSON.stringify(jsonObj)); console.log(JSON.stringify(reader2("$..friends[0]")) == ret1); console.log(JSON.stringify(reader2("$..friends[1]")) == ret2); ``` ### javascript - examples **Demo**: https://freestrings.github.io/jsonpath/ json 데이터 *(참고 사이트: https://github.com/json-path/JsonPath)* ```javascript { "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 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ], "bicycle": { "color": "red", "price": 19.95 } }, "expensive": 10 } ``` | JsonPath (click link to try)| Result | | :------- | :----- | | $.store.book[*].author| The authors of all books | | $..author | All authors | | $.store.* | All things, both books and bicycles | | $.store..price | The price of everything | | $..book[2] | The third book | | $..book[-2] | The second to last book | | $..book[0,1] | The first two books | | $..book[:2] | All books from index 0 (inclusive) until index 2 (exclusive) | | $..book[1:2] | All books from index 1 (inclusive) until index 2 (exclusive) | | $..book[-2:] | Last two books | | $..book[2:] | Book number two from tail | | $..book[?(@.isbn)] | All books with an ISBN number | | $.store.book[?(@.price < 10)] | All books in store cheaper than 10 | | $..* | Give me every thing | $..book[ ?(
(@.price == 12.99 | | $.store.bicycle.price < @.price)
|| @.category == "reference"
)]
| Complex filter ## With Rust (as library) ### jsonpath_lib library ```rust extern crate jsonpath_lib as jsonpath; #[macro_use] extern crate serde_json; ``` ### rust - jsonpath::read(json: serde_json::value::Value, jsonpath: &str) ```rust let json_obj = json!({ "school": { "friends": [{"id": 0}, {"id": 1}] }, "friends": [{"id": 0}, {"id": 1}] }); let json = jsonpath::read(json_obj, "$..friends[0]").unwrap(); let ret = json!([ {"id": 0}, {"id": 0} ]); assert_eq!(json, ret) ``` ### rust - jsonpath::compile(jsonpath: &str) ```rust let mut template = jsonpath::compile("$..friends[0]"); let json_obj = json!({ "school": { "friends": [ {"id": 0}, {"id": 1} ] }, "friends": [ {"id": 0}, {"id": 1} ] }); let json = template(json_obj).unwrap(); let ret = json!([ {"id": 0}, {"id": 0} ]); assert_eq!(json, ret); let json_obj = json!({ "school": { "friends": [ {"name": "Millicent Norman"}, {"name": "Vincent Cannon"} ] }, "friends": [ {"id": 0}, {"id": 1} ] }); let json = template(json_obj).unwrap(); let ret = json!([ {"id": 0}, {"name": "Millicent Norman"} ]); assert_eq!(json, ret); ``` ### rust - jsonpath::reader(json: serde_json::value::Value) ```rust let json_obj = json!({ "school": { "friends": [{"id": 0}, {"id": 1}] }, "friends": [{"id": 0},{"id": 1}] }); let mut reader = jsonpath::reader(json_obj); let json = reader("$..friends[0]").unwrap(); let ret = json!([ {"id": 0}, {"id": 0} ]); assert_eq!(json, ret); let json = reader("$..friends[1]").unwrap(); let ret = json!([ {"id": 1}, {"id": 1} ]); assert_eq!(json, ret); ``` ### rust - examples ```rust let json_obj = json!({ "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 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ], "bicycle": { "color": "red", "price": 19.95 } }, "expensive": 10 }); let mut reader = jsonpath::reader(json_obj); ``` #### $.store.book[*].author ```rust let json = reader("$.store.book[*].author").unwrap(); let ret = json!([ "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien" ]); assert_eq!(json, ret); ``` #### $..author ```rust let json = reader("$..author").unwrap(); let ret = json!([ "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien" ]); assert_eq!(json, ret); ``` #### $.store.* ```rust let json = reader("$.store.*").unwrap(); let ret = json!([ [ { "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 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ], { "color": "red", "price": 19.95 } ]); assert_eq!(ret, json); ``` #### $.store..price ```rust let json = reader("$.store..price").unwrap(); let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]); assert_eq!(ret, json); ``` #### $..book[2] ```rust let json = reader("$..book[2]").unwrap(); let ret = json!([{ "category" : "fiction", "author" : "Herman Melville", "title" : "Moby Dick", "isbn" : "0-553-21311-3", "price" : 8.99 }]); assert_eq!(ret, json); ``` #### $..book[-2] ```rust let json = reader("$..book[-2]").unwrap(); let ret = json!([{ "category" : "fiction", "author" : "Herman Melville", "title" : "Moby Dick", "isbn" : "0-553-21311-3", "price" : 8.99 }]); assert_eq!(ret, json); ``` #### $..book[0,1] ```rust let json = reader("$..book[0,1]").unwrap(); let ret = json!([ { "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 } ]); assert_eq!(ret, json); ``` #### $..book[:2] ```rust let json = reader("$..book[:2]").unwrap(); let ret = json!([ { "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 } ]); assert_eq!(ret, json); ``` #### $..book[2:] ```rust let json = reader("$..book[2:]").unwrap(); let ret = json!([ { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ]); assert_eq!(ret, json); ``` #### $..book[?(@.isbn)] ```rust let json = reader("$..book[?(@.isbn)]").unwrap(); let ret = json!([ { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ]); assert_eq!(ret, json); ``` #### $.store.book[?(@.price < 10)] ```rust let json = reader("$.store.book[?(@.price < 10)]").unwrap(); let ret = json!([ { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 } ]); assert_eq!(ret, json); ``` #### $..book[?((@.price == 12.99 || $.store.bicycle.price < @.price) || @.category == "reference")] ```rust let json = reader(r#"$..book[ ?( (@.price == 12.99 || $.store.bicycle.price < @.price) || @.category == "reference" )]"#).unwrap(); let ret = json!([ { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 }, { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 } ]); assert_eq!(ret, json); ``` ## With AWS API Gateway - ## Simple time check with [dchester/jsonpath](https://github.com/dchester/jsonpath) `jsonpath` is dchester/jsonpath `jsonpath-wasm` is freestrings/jsonpath's compiled to webassembly `jsonpath-wasm` is slow performance on Chrome browser and in NodeJS. not yet usable. :) ### Browser [Bench Demo](https://freestrings.github.io/jsonpath/bench) #### Chrome: 72.0 > Something to wrong in chrome ``` jsonpath, 134 jsonpath-wasm- reader, 1409 jsonpath-wasm- compile, 3237 jsonpath-wasm- read, 5302 ``` #### Firefox: 65.0 > jsonpath-wasm is faster than jsonpath ``` jsonpath, 301 jsonpath-wasm- reader, 166 jsonpath-wasm- compile, 130 jsonpath-wasm- read, 144 ``` ### NodeJs * NodeJS: 11.0 * CPU: Intel Core i5-4460 * Memory: 16GB > Rust > jsonpath > jsonpath-wasm ```bash cd benches && ./bench_node_vs_rust.sh $..book[?(@.price<30 && @.category==fiction)] (loop 100,000) Rust: real 0m1.141s user 0m1.137s sys 0m0.004s NodeJs - jsonpath module: real 0m3.718s user 0m4.175s sys 0m0.050s NodeJs - jsonpath-wasm module: real 0m10.205s user 0m10.281s sys 0m0.383s ```