Rust
버전 JsonPath 구현이다. Rust 구현과 동일한 기능을 Webassembly
로 제공하는 것도 목표.
The Rust
version is a JsonPath implementation. It is also aimed to provide the same functionality as Webassembly
in Rust implementation.
To enjoy Rust!
(not yet published jsonpath-wasm
)
javascript
// browser
import * as jsonpath from "jsonpath-wasm";
// nodejs
let jsonpath = require('jsonpath-wasm');
```javascript let jsonObj = { "school": { "friends": [{"id": 0}, {"id": 1}] }, "friends": [{"id": 0}, {"id": 1}] }; let ret = [{"id": 0}, {"id": 0}];
let a = jsonpath.select(JSON.stringify(jsonObj), "$..friends[0]"); let b = jsonpath.select(jsonObj, "$..friends[0]"); console.log( JSON.stringify(ret) == JSON.stringify(a), JSON.stringify(a) == JSON.stringify(b) ); ```
```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 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 selector = jsonpath.selector(jsonObj); console.log(JSON.stringify(selector("$..friends[0]")) == ret1); console.log(JSON.stringify(selector("$..friends[1]")) == ret2);
// 2. read as json string let selector = jsonpath.selector(JSON.stringify(jsonObj)); console.log(JSON.stringify(selector("$..friends[0]")) == ret1); console.log(JSON.stringify(selector("$..friends[1]")) == ret2); ```
wasm-bindgen은 Javascript와 Webassembly 간 값을 주고받을 때 JSON 객체는 String으로 변환되기 때문에, 반복해서 사용되는 JSON 객체를 Webassembly 영역에 생성해 두면 성능에 도움이 된다.
Since wasm-bindgen converts JSON objects to String when exchanging values between Javascript and Webassembly, it is helpful to create repeated Json objects in Webassembly area.
```javascript
let jsonObj = { "school": { "friends": [{"id": 0}, {"id": 1}] }, "friends": [{"id": 0},{"id": 1}] };
let path = '$..friends[0]'; let template = jsonpath.compile(path); let selector = jsonpath.selector(jsonObj);
let ptr = jsonpath.alloc_json(jsonObj);
if(ptr == 0) console.error('invalid ptr'); // 0
is invalid pointer
let selector2 = jsonpath.selector(ptr);
let ret1 = selector(path) let ret2 = selector2(path) let ret3 = template(jsonObj); let ret4 = template(ptr); let ret5 = jsonpath.select(jsonObj, path); let ret6 = jsonpath.select(ptr, path);
console.log( JSON.stringify(ret1) == JSON.stringify(ret2),// true JSON.stringify(ret1) == JSON.stringify(ret3),// true JSON.stringify(ret1) == JSON.stringify(ret4),// true JSON.stringify(ret1) == JSON.stringify(ret5),// true JSON.stringify(ret1) == JSON.stringify(ret6));// true
jsonpath.dealloc_json(ptr);
```
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
```rust extern crate jsonpath_lib as jsonpath;
extern crate serde_json; ```
rust
let json_obj = json!({
"school": {
"friends": [{"id": 0}, {"id": 1}]
},
"friends": [{"id": 0}, {"id": 1}]
});
let json = jsonpath::select(json_obj, "$..friends[0]").unwrap();
let ret = json!([ {"id": 0}, {"id": 0} ]);
assert_eq!(json, ret)
```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(jsonobj).unwrap(); let ret = json!([ {"id": 0}, {"id": 0} ]); asserteq!(json, ret);
let json_obj = json!({ "school": { "friends": [ {"name": "Millicent Norman"}, {"name": "Vincent Cannon"} ] }, "friends": [ {"id": 0}, {"id": 1} ] });
let json = template(jsonobj).unwrap(); let ret = json!([ {"id": 0}, {"name": "Millicent Norman"} ]); asserteq!(json, ret); ```
```rust let json_obj = json!({ "school": { "friends": [{"id": 0}, {"id": 1}] }, "friends": [{"id": 0},{"id": 1}] });
let mut selector = jsonpath::selector(json_obj);
let json = selector("$..friends[0]").unwrap(); let ret = json!([ {"id": 0}, {"id": 0} ]); assert_eq!(json, ret);
let json = selector("$..friends[1]").unwrap(); let ret = json!([ {"id": 1}, {"id": 1} ]); assert_eq!(json, ret); ```
```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 selector = jsonpath::selector(json_obj);
```
rust
let json = selector("$.store.book[*].author").unwrap();
let ret = json!([
"Nigel Rees",
"Evelyn Waugh",
"Herman Melville",
"J. R. R. Tolkien"
]);
assert_eq!(json, ret);
rust
let json = selector("$..author").unwrap();
let ret = json!([
"Nigel Rees",
"Evelyn Waugh",
"Herman Melville",
"J. R. R. Tolkien"
]);
assert_eq!(json, ret);
rust
let json = selector("$.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);
rust
let json = selector("$.store..price").unwrap();
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
assert_eq!(ret, json);
rust
let json = selector("$..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);
rust
let json = selector("$..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);
rust
let json = selector("$..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);
rust
let json = selector("$..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);
rust
let json = selector("$..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);
rust
let json = selector("$..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);
rust
let json = selector("$.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);
rust
let json = selector(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);
-
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. :)
'$..book[?(@.price<30 && @.category=="fiction")]' (loop 2,000)
Something to wrong in chrome
jsonpath, 166
jsonpath-wasm- selector, 256
jsonpath-wasm- compile, 1168
jsonpath-wasm- compile-alloc, 645
jsonpath-wasm- select, 3224
jsonpath-wasm- select-alloc, 1427
jsonpath-wasm is faster than jsonpath
jsonpath, 125
jsonpath-wasm- selector, 101
jsonpath-wasm- compile, 169
jsonpath-wasm- compile-alloc, 78
jsonpath-wasm- select, 186
jsonpath-wasm- select-alloc, 93
Rust > jsonpath > jsonpath-wasm
```bash cd benches && ./benchnodevs_rust.sh $..book[?(@.price<30 && @.category==fiction)] (loop 100,000)
Rust:
real 0m0.862s user 0m0.862s sys 0m0.000s
NodeJs - jsonpath module:
real 0m3.667s user 0m4.139s sys 0m0.045s
NodeJs - jsonpath-wasm module - selector:
real 0m5.331s user 0m5.494s sys 0m0.093s
NodeJs - jsonpath-wasm module - compile:
real 0m8.665s user 0m8.809s sys 0m0.197s
NodeJs - jsonpath-wasm module - compile-alloc:
real 0m4.014s user 0m4.173s sys 0m0.088s
NodeJs - jsonpath-wasm module - select:
real 0m9.843s user 0m9.897s sys 0m0.244s
NodeJs - jsonpath-wasm module - select-alloc: Invalid function name
real 0m5.212s user 0m5.339s sys 0m0.096s
```