mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-07-13 22:51:39 +00:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
1c3656460e | |||
d263e30c91 | |||
ceadbcec84 | |||
a15abe38fb | |||
7a106539d1 | |||
4ad783e40c | |||
0729a2a47f | |||
30aa38379a | |||
d955a1632c | |||
8ec694090b | |||
d75b93612d |
2
.idea/runConfigurations/all.xml
generated
2
.idea/runConfigurations/all.xml
generated
@ -3,7 +3,7 @@
|
|||||||
<option name="channel" value="DEFAULT" />
|
<option name="channel" value="DEFAULT" />
|
||||||
<option name="command" value="test --package jsonpath_lib" />
|
<option name="command" value="test --package jsonpath_lib" />
|
||||||
<option name="allFeatures" value="false" />
|
<option name="allFeatures" value="false" />
|
||||||
<option name="nocapture" value="false" />
|
<option name="nocapture" value="true" />
|
||||||
<option name="backtrace" value="SHORT" />
|
<option name="backtrace" value="SHORT" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<envs />
|
<envs />
|
||||||
|
12
.idea/runConfigurations/selector.xml
generated
Normal file
12
.idea/runConfigurations/selector.xml
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="selector" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
|
<option name="channel" value="DEFAULT" />
|
||||||
|
<option name="command" value="test --package jsonpath_lib --test selector """ />
|
||||||
|
<option name="allFeatures" value="false" />
|
||||||
|
<option name="nocapture" value="false" />
|
||||||
|
<option name="backtrace" value="SHORT" />
|
||||||
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
|
<envs />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
2
.idea/runConfigurations/serde.xml
generated
2
.idea/runConfigurations/serde.xml
generated
@ -3,7 +3,7 @@
|
|||||||
<option name="channel" value="DEFAULT" />
|
<option name="channel" value="DEFAULT" />
|
||||||
<option name="command" value="test --package jsonpath_lib --test serde """ />
|
<option name="command" value="test --package jsonpath_lib --test serde """ />
|
||||||
<option name="allFeatures" value="false" />
|
<option name="allFeatures" value="false" />
|
||||||
<option name="nocapture" value="true" />
|
<option name="nocapture" value="false" />
|
||||||
<option name="backtrace" value="SHORT" />
|
<option name="backtrace" value="SHORT" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<envs />
|
<envs />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "jsonpath_lib"
|
name = "jsonpath_lib"
|
||||||
version = "0.1.8"
|
version = "0.1.9"
|
||||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||||
|
|
||||||
description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath"
|
description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath"
|
||||||
|
580
README.md
580
README.md
@ -5,51 +5,285 @@
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. `Webassembly`와 `Javascript`에서도 역시 동일한 API 인터페이스를 제공 한다.
|
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. `Webassembly`와 `Javascript`에서도 유사한 API 인터페이스를 제공 한다.
|
||||||
|
|
||||||
It is an implementation for [JsonPath](https://goessner.net/articles/JsonPath/) written in `Rust`. it provide the same API interface in `Webassembly` and` Javascript` also.
|
It is an implementation for [JsonPath](https://goessner.net/articles/JsonPath/) written in `Rust`. it provide a similar API interface in `Webassembly` and` Javascript` also.
|
||||||
|
|
||||||
- [Webassembly Demo](https://freestrings.github.io/jsonpath/)
|
- [Webassembly Demo](https://freestrings.github.io/jsonpath/)
|
||||||
- [Rust documentation](https://docs.rs/jsonpath_lib/0.1.6/jsonpath_lib)
|
- [Rust documentation](https://docs.rs/jsonpath_lib)
|
||||||
|
|
||||||
## Why?
|
## Why?
|
||||||
|
|
||||||
To enjoy Rust!
|
To enjoy Rust!
|
||||||
|
|
||||||
## API
|
## Rust API
|
||||||
|
|
||||||
[With Javascript](#with-javascript)
|
- [jsonpath_lib crate](#jsonpath_lib-crate)
|
||||||
|
- [Rust - jsonpath::Selector struct](#rust---jsonpathselector-struct)
|
||||||
|
- [Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)](#rust---jsonpathselectjson-serde_jsonvaluevalue-jsonpath-str)
|
||||||
|
- [Rust - jsonpath::select_as_str(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_as_strjson-str-jsonpath-str)
|
||||||
|
- [Rust - jsonpath::select_as\<T: `serde::de::DeserializeOwned`\>(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_ast-serdededeserializeownedjson-str-jsonpath-str)
|
||||||
|
- [Rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str)
|
||||||
|
- [Rust - jsonpath::selector(json: &serde_json::value::Value)](#rust---jsonpathselectorjson-serde_jsonvaluevalue)
|
||||||
|
- [Rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value)](#rust---jsonpathselector_ast-serdededeserializeownedjson-serde_jsonvaluevalue)
|
||||||
|
- [Rust - examples](https://github.com/freestrings/jsonpath/wiki/rust-examples)
|
||||||
|
|
||||||
- [jsonpath-wasm library](#jsonpath-wasm-library)
|
## Javascript API
|
||||||
- [jsonpath-rs library](#jsonpath-rs-library-only-nodejs)
|
|
||||||
- [javascript - jsonpath.select(json: string|object, jsonpath: string)](#javascript---jsonpathselectjson-stringobject-jsonpath-string)
|
|
||||||
- [javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string)
|
|
||||||
- [javascript - jsonpath.selector(json: string|object)](#javascript---jsonpathselectorjson-stringobject)
|
|
||||||
- [javascript - alloc_json, dealloc_json](#javascript---alloc_json-dealloc_json)
|
|
||||||
- [javascript-wasm - examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)
|
|
||||||
|
|
||||||
[With Rust (as library)](#with-rust-as-library)
|
- [npm package](#npm-package)
|
||||||
|
- [Javascript - jsonpath.Selector class](#javascript---selector-class)
|
||||||
|
- [Javascript - jsonpath.select(json: string|object, jsonpath: string)](#javascript---jsonpathselectjson-stringobject-jsonpath-string)
|
||||||
|
- [Javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string)
|
||||||
|
- [Javascript - jsonpath.selector(json: string|object)](#javascript---jsonpathselectorjson-stringobject)
|
||||||
|
- [Javascript - allocJson, deallocJson (Webassembly Only)](#javascript---allocjson-deallocjson-webassembly-only)
|
||||||
|
- [Javascript - examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)
|
||||||
|
|
||||||
- [jsonpath_lib library](#jsonpath_lib-library)
|
## Simple time check
|
||||||
- [rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)](#rust---jsonpathselectjson-serde_jsonvaluevalue-jsonpath-str)
|
- [jsonpath-wasm](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck---jsonpath-wasm)
|
||||||
- [rust - jsonpath::select_as_str(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_as_strjson-str-jsonpath-str)
|
- [jsonpath-rs](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck-jsonpath-native)
|
||||||
- [rust - jsonpath::select_as\<T: `serde::de::DeserializeOwned`\>(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_ast-serdededeserializeownedjson-str-jsonpath-str)
|
|
||||||
- [rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str)
|
|
||||||
- [rust - jsonpath::selector(json: &serde_json::value::Value)](#rust---jsonpathselectorjson-serde_jsonvaluevalue)
|
|
||||||
- [rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value)](#rust---jsonpathselector_ast-serdededeserializeownedjson-serde_jsonvaluevalue)
|
|
||||||
- [rust - examples](https://github.com/freestrings/jsonpath/wiki/rust-examples)
|
|
||||||
|
|
||||||
[With AWS API Gateway](#)
|
---
|
||||||
|
|
||||||
[Simple time check - webassembly](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck---jsonpath-wasm)
|
### Rust API
|
||||||
|
|
||||||
[Simple time check - native addon for NodeJs](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck-jsonpath-native)
|
#### jsonpath_lib crate
|
||||||
|
[Go to creates.io](https://crates.io/crates/jsonpath_lib)
|
||||||
|
|
||||||
## With Javascript
|
```rust
|
||||||
|
extern crate jsonpath_lib as jsonpath;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_json;
|
||||||
|
```
|
||||||
|
|
||||||
### jsonpath-wasm library
|
#### Rust - jsonpath::Selector struct
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Friend {
|
||||||
|
name: String,
|
||||||
|
age: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let json_obj = json!({
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]});
|
||||||
|
|
||||||
|
let mut selector = Selector::new();
|
||||||
|
|
||||||
|
let result = selector
|
||||||
|
.path("$..[?(@.age >= 30)]").unwrap()
|
||||||
|
// .value_from_str(&serde_json::to_string(&json_obj).unwrap() /*&str*/).unwrap()
|
||||||
|
// .value_from(&json_obj /*&impl serde::ser::Serialize*/).unwrap()
|
||||||
|
.value((&json_obj /*serde_json::value::Value*/ ).into()).unwrap()
|
||||||
|
.select_to_value().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(json!([{"name": "친구3", "age": 30}]), result);
|
||||||
|
|
||||||
|
let result = selector.select_to_str().unwrap();
|
||||||
|
assert_eq!(r#"[{"name":"친구3","age":30}]"#, result);
|
||||||
|
|
||||||
|
let result = selector.select_to::<Vec<Friend>>().unwrap();
|
||||||
|
assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let json_obj = json!({
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]});
|
||||||
|
|
||||||
|
let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();
|
||||||
|
|
||||||
|
let ret = json!([
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구1", "age": 20}
|
||||||
|
]);
|
||||||
|
assert_eq!(json, ret);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rust - jsonpath::select_as_str(json: &str, jsonpath: &str)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let ret = jsonpath::select_as_str(r#"
|
||||||
|
{
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"#, "$..friends[0]").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rust - jsonpath::select_as\<T: `serde::de::DeserializeOwned`\>(json: &str, jsonpath: &str)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Deserialize, PartialEq, Debug)]
|
||||||
|
struct Person {
|
||||||
|
name: String,
|
||||||
|
age: u8,
|
||||||
|
phones: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret: Person = jsonpath::select_as(r#"
|
||||||
|
{
|
||||||
|
"person":
|
||||||
|
{
|
||||||
|
"name": "Doe John",
|
||||||
|
"age": 44,
|
||||||
|
"phones": [
|
||||||
|
"+44 1234567",
|
||||||
|
"+44 2345678"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#, "$.person").unwrap();
|
||||||
|
|
||||||
|
let person = Person {
|
||||||
|
name: "Doe John".to_string(),
|
||||||
|
age: 44,
|
||||||
|
phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(person, ret);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rust - jsonpath::compile(jsonpath: &str)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut template = jsonpath::compile("$..friends[0]");
|
||||||
|
|
||||||
|
let json_obj = json!({
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]});
|
||||||
|
|
||||||
|
let json = template(&json_obj).unwrap();
|
||||||
|
|
||||||
|
let ret = json!([
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구1", "age": 20}
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(json, ret);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rust - jsonpath::selector(json: &serde_json::value::Value)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let json_obj = json!({
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]});
|
||||||
|
|
||||||
|
let mut selector = jsonpath::selector(&json_obj);
|
||||||
|
|
||||||
|
let json = selector("$..friends[0]").unwrap();
|
||||||
|
|
||||||
|
let ret = json!([
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구1", "age": 20}
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(json, ret);
|
||||||
|
|
||||||
|
let json = selector("$..friends[1]").unwrap();
|
||||||
|
|
||||||
|
let ret = json!([
|
||||||
|
{"name": "친구4"},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(json, ret);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let json_obj = json!({
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]});
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Friend {
|
||||||
|
name: String,
|
||||||
|
age: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut selector = jsonpath::selector_as::<Vec<Friend>>(&json_obj);
|
||||||
|
|
||||||
|
let json = selector("$..friends[0]").unwrap();
|
||||||
|
|
||||||
|
let ret = vec!(
|
||||||
|
Friend { name: "친구3".to_string(), age: Some(30) },
|
||||||
|
Friend { name: "친구1".to_string(), age: Some(20) }
|
||||||
|
);
|
||||||
|
assert_eq!(json, ret);
|
||||||
|
|
||||||
|
let json = selector("$..friends[1]").unwrap();
|
||||||
|
|
||||||
|
let ret = vec!(
|
||||||
|
Friend { name: "친구4".to_string(), age: None },
|
||||||
|
Friend { name: "친구2".to_string(), age: Some(20) }
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(json, ret);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Javascript API
|
||||||
|
|
||||||
|
#### npm package
|
||||||
|
|
||||||
|
##### jsonpath-wasm (Not yet published)
|
||||||
|
|
||||||
*(not yet published `jsonpath-wasm`)*
|
|
||||||
```javascript
|
```javascript
|
||||||
// browser
|
// browser
|
||||||
import * as jsonpath from "jsonpath-wasm";
|
import * as jsonpath from "jsonpath-wasm";
|
||||||
@ -57,15 +291,92 @@ import * as jsonpath from "jsonpath-wasm";
|
|||||||
const jsonpath = require('jsonpath-wasm');
|
const jsonpath = require('jsonpath-wasm');
|
||||||
```
|
```
|
||||||
|
|
||||||
### jsonpath-rs library (Only NodeJS)
|
##### jsonpath-rs (NodeJS only)
|
||||||
|
|
||||||
`jsonpath-rs` is native addon for NodeJs
|
[Goto npmjs.org](https://www.npmjs.com/package/jsonpath-rs)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const jsonpath = require('jsonpath-rs');
|
const jsonpath = require('jsonpath-rs');
|
||||||
```
|
```
|
||||||
|
|
||||||
### javascript - jsonpath.select(json: string|object, jsonpath: string)
|
#### javascript - Selector class
|
||||||
|
|
||||||
|
##### jsonpath-wasm
|
||||||
|
`wasm-bindgen` 리턴타입 제약 때문에 빌더 패턴은 지원하지 않는다.
|
||||||
|
|
||||||
|
It does not support `builder-pattern` due to the `return type` restriction of `wasm-bindgen`.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let jsonObj = {
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구1", "age": 20}
|
||||||
|
];
|
||||||
|
|
||||||
|
let selector = new jsonpath.Selector();
|
||||||
|
selector.path('$..friends[0]');
|
||||||
|
selector.value(jsonObj);
|
||||||
|
|
||||||
|
let selectToObj = selector.selectTo();
|
||||||
|
let selectToString = selector.selectToStr();
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
JSON.stringify(ret) == JSON.stringify(selectToObj),
|
||||||
|
JSON.stringify(ret) == selectToString
|
||||||
|
);
|
||||||
|
|
||||||
|
// => true, true
|
||||||
|
```
|
||||||
|
|
||||||
|
##### jsonpath-rs
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let jsonObj = {
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구1", "age": 20}
|
||||||
|
];
|
||||||
|
|
||||||
|
let selector = new jsonpath.Selector()
|
||||||
|
.path('$..friends[0]')
|
||||||
|
.value(jsonObj);
|
||||||
|
|
||||||
|
let selectToObj = selector.selectTo();
|
||||||
|
let selectToString = selector.selectToStr();
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
JSON.stringify(ret) == JSON.stringify(selectToObj),
|
||||||
|
JSON.stringify(ret) == selectToString
|
||||||
|
);
|
||||||
|
|
||||||
|
// => true, true
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Javascript - jsonpath.select(json: string|object, jsonpath: string)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let jsonObj = {
|
let jsonObj = {
|
||||||
@ -98,7 +409,7 @@ console.log(
|
|||||||
// => true, true
|
// => true, true
|
||||||
```
|
```
|
||||||
|
|
||||||
### javascript - jsonpath.compile(jsonpath: string)
|
#### Javascript - jsonpath.compile(jsonpath: string)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let template = jsonpath.compile('$..friends[0]');
|
let template = jsonpath.compile('$..friends[0]');
|
||||||
@ -157,7 +468,7 @@ console.log(
|
|||||||
// => true, true
|
// => true, true
|
||||||
```
|
```
|
||||||
|
|
||||||
### javascript - jsonpath.selector(json: string|object)
|
#### Javascript - jsonpath.selector(json: string|object)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let jsonObj = {
|
let jsonObj = {
|
||||||
@ -198,13 +509,10 @@ console.log(
|
|||||||
// => true, true
|
// => true, true
|
||||||
```
|
```
|
||||||
|
|
||||||
### javascript - alloc_json, dealloc_json
|
#### Javascript - allocJson, deallocJson (Webassembly Only)
|
||||||
|
wasm-bindgen은 Javascript와 Webassembly간 값을 주고받을 때 JSON 객체는 String으로 변환되기 때문에, 반복해서 사용되는 JSON 객체는 Webassembly 영역에 생성해 두면 성능에 도움이 된다.
|
||||||
|
|
||||||
*(not supported in `jsonpath-rs`)*
|
Since wasm-bindgen converts JSON objects to String when exchanging values between Javascript and Webassembly, creating frequently used JSON objects in the WebAssembly area helps performance.
|
||||||
|
|
||||||
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
|
```javascript
|
||||||
const jsonpath = require('@nodejs/jsonpath-wasm');
|
const jsonpath = require('@nodejs/jsonpath-wasm');
|
||||||
@ -223,7 +531,7 @@ let jsonObj = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// allocate jsonObj in webassembly
|
// allocate jsonObj in webassembly
|
||||||
let ptr = jsonpath.alloc_json(jsonObj);
|
let ptr = jsonpath.allocJson(jsonObj);
|
||||||
|
|
||||||
// `0` is invalid pointer
|
// `0` is invalid pointer
|
||||||
if(ptr == 0) {
|
if(ptr == 0) {
|
||||||
@ -254,197 +562,5 @@ console.log(
|
|||||||
|
|
||||||
// => true true true true true
|
// => true true true true true
|
||||||
|
|
||||||
jsonpath.dealloc_json(ptr);
|
jsonpath.deallocJson(ptr);
|
||||||
```
|
|
||||||
|
|
||||||
## With Rust (as library)
|
|
||||||
|
|
||||||
### jsonpath_lib library
|
|
||||||
|
|
||||||
```rust
|
|
||||||
extern crate jsonpath_lib as jsonpath;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_json;
|
|
||||||
```
|
|
||||||
|
|
||||||
### rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let json_obj = json!({
|
|
||||||
"school": {
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구1", "age": 20},
|
|
||||||
{"name": "친구2", "age": 20}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구3", "age": 30},
|
|
||||||
{"name": "친구4"}
|
|
||||||
]});
|
|
||||||
|
|
||||||
let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();
|
|
||||||
|
|
||||||
let ret = json!([
|
|
||||||
{"name": "친구3", "age": 30},
|
|
||||||
{"name": "친구1", "age": 20}
|
|
||||||
]);
|
|
||||||
assert_eq!(json, ret);
|
|
||||||
```
|
|
||||||
|
|
||||||
### rust - jsonpath::select_as_str(json: &str, jsonpath: &str)
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let ret = jsonpath::select_as_str(r#"
|
|
||||||
{
|
|
||||||
"school": {
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구1", "age": 20},
|
|
||||||
{"name": "친구2", "age": 20}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구3", "age": 30},
|
|
||||||
{"name": "친구4"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
"#, "$..friends[0]").unwrap();
|
|
||||||
|
|
||||||
assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
|
|
||||||
```
|
|
||||||
|
|
||||||
### rust - jsonpath::select_as\<T: `serde::de::DeserializeOwned`\>(json: &str, jsonpath: &str)
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[derive(Deserialize, PartialEq, Debug)]
|
|
||||||
struct Person {
|
|
||||||
name: String,
|
|
||||||
age: u8,
|
|
||||||
phones: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let ret: Person = jsonpath::select_as(r#"
|
|
||||||
{
|
|
||||||
"person":
|
|
||||||
{
|
|
||||||
"name": "Doe John",
|
|
||||||
"age": 44,
|
|
||||||
"phones": [
|
|
||||||
"+44 1234567",
|
|
||||||
"+44 2345678"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#, "$.person").unwrap();
|
|
||||||
|
|
||||||
let person = Person {
|
|
||||||
name: "Doe John".to_string(),
|
|
||||||
age: 44,
|
|
||||||
phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(person, ret);
|
|
||||||
```
|
|
||||||
|
|
||||||
### rust - jsonpath::compile(jsonpath: &str)
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let mut template = jsonpath::compile("$..friends[0]");
|
|
||||||
|
|
||||||
let json_obj = json!({
|
|
||||||
"school": {
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구1", "age": 20},
|
|
||||||
{"name": "친구2", "age": 20}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구3", "age": 30},
|
|
||||||
{"name": "친구4"}
|
|
||||||
]});
|
|
||||||
|
|
||||||
let json = template(&json_obj).unwrap();
|
|
||||||
|
|
||||||
let ret = json!([
|
|
||||||
{"name": "친구3", "age": 30},
|
|
||||||
{"name": "친구1", "age": 20}
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_eq!(json, ret);
|
|
||||||
```
|
|
||||||
|
|
||||||
### rust - jsonpath::selector(json: &serde_json::value::Value)
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let json_obj = json!({
|
|
||||||
"school": {
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구1", "age": 20},
|
|
||||||
{"name": "친구2", "age": 20}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구3", "age": 30},
|
|
||||||
{"name": "친구4"}
|
|
||||||
]});
|
|
||||||
|
|
||||||
let mut selector = jsonpath::selector(&json_obj);
|
|
||||||
|
|
||||||
let json = selector("$..friends[0]").unwrap();
|
|
||||||
|
|
||||||
let ret = json!([
|
|
||||||
{"name": "친구3", "age": 30},
|
|
||||||
{"name": "친구1", "age": 20}
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_eq!(json, ret);
|
|
||||||
|
|
||||||
let json = selector("$..friends[1]").unwrap();
|
|
||||||
|
|
||||||
let ret = json!([
|
|
||||||
{"name": "친구4"},
|
|
||||||
{"name": "친구2", "age": 20}
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert_eq!(json, ret);
|
|
||||||
```
|
|
||||||
|
|
||||||
### rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value)
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let json_obj = json!({
|
|
||||||
"school": {
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구1", "age": 20},
|
|
||||||
{"name": "친구2", "age": 20}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"friends": [
|
|
||||||
{"name": "친구3", "age": 30},
|
|
||||||
{"name": "친구4"}
|
|
||||||
]});
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
struct Friend {
|
|
||||||
name: String,
|
|
||||||
age: Option<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut selector = jsonpath::selector_as::<Vec<Friend>>(&json_obj);
|
|
||||||
|
|
||||||
let json = selector("$..friends[0]").unwrap();
|
|
||||||
|
|
||||||
let ret = vec!(
|
|
||||||
Friend { name: "친구3".to_string(), age: Some(30) },
|
|
||||||
Friend { name: "친구1".to_string(), age: Some(20) }
|
|
||||||
);
|
|
||||||
assert_eq!(json, ret);
|
|
||||||
|
|
||||||
let json = selector("$..friends[1]").unwrap();
|
|
||||||
|
|
||||||
let ret = vec!(
|
|
||||||
Friend { name: "친구4".to_string(), age: None },
|
|
||||||
Friend { name: "친구2".to_string(), age: Some(20) }
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(json, ret);
|
|
||||||
```
|
```
|
@ -3,6 +3,7 @@ extern crate jsonpath_lib as jsonpath;
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
extern crate bencher;
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
@ -10,6 +11,8 @@ use serde::Deserialize;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use self::test::Bencher;
|
use self::test::Bencher;
|
||||||
|
use jsonpath::ref_value::model::RefValue;
|
||||||
|
use serde::ser::Serialize;
|
||||||
|
|
||||||
fn read_json(path: &str) -> String {
|
fn read_json(path: &str) -> String {
|
||||||
let mut f = std::fs::File::open(path).unwrap();
|
let mut f = std::fs::File::open(path).unwrap();
|
||||||
@ -102,3 +105,24 @@ fn bench_select_as(b: &mut Bencher) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_serde_ser(b: &mut Bencher) {
|
||||||
|
let json = get_json();
|
||||||
|
|
||||||
|
b.iter(move || {
|
||||||
|
for _ in 1..100 {
|
||||||
|
let _: RefValue = json.serialize(jsonpath::ref_value::ser::Serializer).unwrap().into();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_serde_de(b: &mut Bencher) {
|
||||||
|
let json_string = get_string();
|
||||||
|
let json_str = json_string.as_str();
|
||||||
|
|
||||||
|
b.iter(move || for _ in 1..100 {
|
||||||
|
let _: RefValue = serde_json::from_str(json_str).unwrap();
|
||||||
|
});
|
||||||
|
}
|
@ -37,6 +37,8 @@ __extra () {
|
|||||||
printf "\n"
|
printf "\n"
|
||||||
sleep 1
|
sleep 1
|
||||||
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm - compile-alloc: " && time ./bench.sh wasmCompileAlloc ${ITER}
|
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm - compile-alloc: " && time ./bench.sh wasmCompileAlloc ${ITER}
|
||||||
|
sleep 1
|
||||||
|
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm - Selector: " && time ./bench.sh wasmSelectorClass ${ITER}
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$1" = "extra" ]; then
|
if [ "$1" = "extra" ]; then
|
||||||
|
@ -86,7 +86,7 @@ function wasmCompile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function wasmCompileAlloc() {
|
function wasmCompileAlloc() {
|
||||||
let ptr = jpw.alloc_json(getJson());
|
let ptr = jpw.allocJson(getJson());
|
||||||
if (ptr == 0) {
|
if (ptr == 0) {
|
||||||
console.error('Invalid pointer');
|
console.error('Invalid pointer');
|
||||||
return;
|
return;
|
||||||
@ -98,7 +98,7 @@ function wasmCompileAlloc() {
|
|||||||
let _ = template(ptr);
|
let _ = template(ptr);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
jpw.dealloc_json(ptr);
|
jpw.deallocJson(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ function wasmSelect() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function wasmSelectAlloc() {
|
function wasmSelectAlloc() {
|
||||||
let ptr = jpw.alloc_json(getJson());
|
let ptr = jpw.allocJson(getJson());
|
||||||
if (ptr == 0) {
|
if (ptr == 0) {
|
||||||
console.error('Invalid pointer');
|
console.error('Invalid pointer');
|
||||||
return;
|
return;
|
||||||
@ -120,7 +120,16 @@ function wasmSelectAlloc() {
|
|||||||
let _ = jpw.select(ptr, path);
|
let _ = jpw.select(ptr, path);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
jpw.dealloc_json(ptr);
|
jpw.deallocJson(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function wasmSelectorClass() {
|
||||||
|
let selector = new jpw.Selector();
|
||||||
|
for (var i = 0; i < iter; i++) {
|
||||||
|
selector.path(path);
|
||||||
|
selector.value(jsonStr);
|
||||||
|
let _ = selector.selectToStr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
build.sh
4
build.sh
@ -54,11 +54,11 @@ echo
|
|||||||
echo
|
echo
|
||||||
__msg "wasm-pack"
|
__msg "wasm-pack"
|
||||||
cd "${WASM}" && \
|
cd "${WASM}" && \
|
||||||
wasm-pack build --target=nodejs --scope nodejs --out-dir nodejs_pkg && \
|
wasm-pack build --release --target=nodejs --scope nodejs --out-dir nodejs_pkg && \
|
||||||
cd "${WASM_NODEJS_PKG}" && npm link
|
cd "${WASM_NODEJS_PKG}" && npm link
|
||||||
|
|
||||||
cd "${WASM}" && \
|
cd "${WASM}" && \
|
||||||
wasm-pack build --target=browser --scope browser --out-dir browser_pkg && \
|
wasm-pack build --release --target=browser --scope browser --out-dir browser_pkg && \
|
||||||
cd "${WASM_BROWSER_PKG}" && npm link
|
cd "${WASM_BROWSER_PKG}" && npm link
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
File diff suppressed because one or more lines are too long
BIN
docs/68fa958468b8cdcb12e4.module.wasm
Normal file
BIN
docs/68fa958468b8cdcb12e4.module.wasm
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
docs/bench/68fa958468b8cdcb12e4.module.wasm
Normal file
BIN
docs/bench/68fa958468b8cdcb12e4.module.wasm
Normal file
Binary file not shown.
13
docs/bench/bootstrap.js
vendored
13
docs/bench/bootstrap.js
vendored
@ -88,11 +88,14 @@
|
|||||||
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_closure_wrapper102": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbindgen_rethrow": function(p0i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper102"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_rethrow"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_closure_wrapper104": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbindgen_closure_wrapper103": function(p0i32,p1i32,p2i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper104"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper103"](p0i32,p1i32,p2i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_closure_wrapper105": function(p0i32,p1i32,p2i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper105"](p0i32,p1i32,p2i32);
|
||||||
/******/ }
|
/******/ }
|
||||||
/******/ }
|
/******/ }
|
||||||
/******/ };
|
/******/ };
|
||||||
@ -192,7 +195,7 @@
|
|||||||
/******/ promises.push(installedWasmModuleData);
|
/******/ promises.push(installedWasmModuleData);
|
||||||
/******/ else {
|
/******/ else {
|
||||||
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"c615fa3fad4c084c8bcd"}[wasmModuleId] + ".module.wasm");
|
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"68fa958468b8cdcb12e4"}[wasmModuleId] + ".module.wasm");
|
||||||
/******/ var promise;
|
/******/ var promise;
|
||||||
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||||
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||||
|
Binary file not shown.
13
docs/bootstrap.js
vendored
13
docs/bootstrap.js
vendored
@ -88,11 +88,14 @@
|
|||||||
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_closure_wrapper102": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbindgen_rethrow": function(p0i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper102"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_rethrow"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_closure_wrapper104": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbindgen_closure_wrapper103": function(p0i32,p1i32,p2i32) {
|
||||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper104"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper103"](p0i32,p1i32,p2i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_closure_wrapper105": function(p0i32,p1i32,p2i32) {
|
||||||
|
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper105"](p0i32,p1i32,p2i32);
|
||||||
/******/ }
|
/******/ }
|
||||||
/******/ }
|
/******/ }
|
||||||
/******/ };
|
/******/ };
|
||||||
@ -192,7 +195,7 @@
|
|||||||
/******/ promises.push(installedWasmModuleData);
|
/******/ promises.push(installedWasmModuleData);
|
||||||
/******/ else {
|
/******/ else {
|
||||||
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"c615fa3fad4c084c8bcd"}[wasmModuleId] + ".module.wasm");
|
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"68fa958468b8cdcb12e4"}[wasmModuleId] + ".module.wasm");
|
||||||
/******/ var promise;
|
/******/ var promise;
|
||||||
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||||
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||||
|
Binary file not shown.
@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>JsonPath evaluator - Webassembly via Rust</title>
|
<title>JsonPath evaluator - Webassembly via Rust</title>
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
|
||||||
|
<link href="./css/github-corner.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body role="document">
|
<body role="document">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -15,7 +16,59 @@
|
|||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-3">
|
||||||
|
<span class="badge badge-dark" style="margin-bottom: 15px">JsonPath</span> <span>(click to try)</span>
|
||||||
|
<table class="table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#/$.store.book[*].author">$.store.book[*].author</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#$..author">$..author</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$.store.*</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$.store..price</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[2]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[-2]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[0,1]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[:2]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[1:2]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[-2:]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[2:]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[?(@.isbn)]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$.store.book[?(@.price < 10)]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..*</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
<span class="badge badge-dark" style="margin-bottom: 15px">Evaluator</span>
|
<span class="badge badge-dark" style="margin-bottom: 15px">Evaluator</span>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<textarea id="json-example" class="form-control" style="min-width: 100%" rows="20"></textarea>
|
<textarea id="json-example" class="form-control" style="min-width: 100%" rows="20"></textarea>
|
||||||
@ -29,12 +82,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-4">
|
||||||
<span class="badge badge-dark" style="margin-bottom: 15px">Result</span>
|
<span class="badge badge-dark" style="margin-bottom: 15px">Result</span>
|
||||||
<pre class="prettyprint result" id="read-result" style="background-color: transparent; border: none;"></pre>
|
<pre class="prettyprint result" id="read-result" style="background-color: transparent; border: none;"></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="https://github.com/freestrings/jsonpath" class="github-corner" aria-label="View source on GitHub">
|
||||||
|
<svg width="80" height="80" viewBox="0 0 250 250" style="position: absolute; top: 0px; right: 0px; border: 0px;" aria-hidden="true">
|
||||||
|
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" fill="#151513"></path>
|
||||||
|
<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="#ffffff" style="transform-origin: 130px 106px;"></path>
|
||||||
|
<path class="octo-body" d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="#ffffff"></path>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
<script src="./bootstrap.js"></script>
|
<script src="./bootstrap.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -12,14 +12,52 @@ Build from source instead of using pre-built binary, and if Rust is not installe
|
|||||||
|
|
||||||
> Not yet tested in Windows
|
> Not yet tested in Windows
|
||||||
|
|
||||||
## 목차
|
## APIs
|
||||||
|
|
||||||
|
* [jsonpath.Selector](#jsonpathselector)
|
||||||
* [jsonpath.select(json: string|object, jsonpath: string)](#json-stringobject-jsonpath-string)
|
* [jsonpath.select(json: string|object, jsonpath: string)](#json-stringobject-jsonpath-string)
|
||||||
* [jsonpath.compile(jsonpath: string)](#compilejsonpath-string)
|
* [jsonpath.compile(jsonpath: string)](#compilejsonpath-string)
|
||||||
* [jsonpath.selector(json: string|object)](#selectorjson-stringobject)
|
* [jsonpath.selector(json: string|object)](#selectorjson-stringobject)
|
||||||
* [Simple time check](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck-jsonpath-native)
|
* [Simple time check](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck-jsonpath-native)
|
||||||
* [Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)
|
* [Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)
|
||||||
|
|
||||||
|
### jsonpath.Selector
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let jsonObj = {
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let selector = new jsonpath.Selector().value(jsonObj);
|
||||||
|
|
||||||
|
{
|
||||||
|
let jsonObj = selector.path('$..[?(@.age >= 30)]').selectTo();
|
||||||
|
let resultObj = [{"name": "친구3", "age": 30}];
|
||||||
|
console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let jsonObj = selector.path('$..[?(@.age == 20)]').selectTo();
|
||||||
|
let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}];
|
||||||
|
console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let jsonObj = selector.value({"friends": [ {"name": "친구5", "age": 20} ]}).selectTo();
|
||||||
|
let resultObj = [{"name": "친구5", "age": 20}];
|
||||||
|
console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### jsonpath.select(json: string|object, jsonpath: string)
|
### jsonpath.select(json: string|object, jsonpath: string)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const { Compile, Selector, selectStr } = require('../native');
|
const { CompileFn, SelectorFn, selectStr, Selector: _Selector } = require('../native');
|
||||||
|
|
||||||
function compile(path) {
|
function compile(path) {
|
||||||
let compile = new Compile(path);
|
let compile = new CompileFn(path);
|
||||||
return (json) => {
|
return (json) => {
|
||||||
if(typeof json != 'string') {
|
if(typeof json != 'string') {
|
||||||
json = JSON.stringify(json)
|
json = JSON.stringify(json)
|
||||||
@ -14,9 +14,9 @@ function selector(json) {
|
|||||||
if(typeof json != 'string') {
|
if(typeof json != 'string') {
|
||||||
json = JSON.stringify(json)
|
json = JSON.stringify(json)
|
||||||
}
|
}
|
||||||
let selector = new Selector(json);
|
let selector = new SelectorFn(json);
|
||||||
return (path) => {
|
return (path) => {
|
||||||
return JSON.parse(selector.selector(path));
|
return JSON.parse(selector.select(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,8 +27,38 @@ function select(json, path) {
|
|||||||
return JSON.parse(selectStr(json, path));
|
return JSON.parse(selectStr(json, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Selector {
|
||||||
|
constructor() {
|
||||||
|
this._selector = new _Selector();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
path(path) {
|
||||||
|
this._selector.path(path);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
value(json) {
|
||||||
|
if(typeof json != 'string') {
|
||||||
|
json = JSON.stringify(json)
|
||||||
|
}
|
||||||
|
this._selector.value_from_str(json);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectToStr() {
|
||||||
|
return this._selector.select_to_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
selectTo() {
|
||||||
|
return JSON.parse(this.selectToStr());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
compile,
|
compile,
|
||||||
selector,
|
selector,
|
||||||
select
|
select,
|
||||||
|
Selector
|
||||||
};
|
};
|
@ -14,7 +14,7 @@ exclude = ["artifacts.json", "index.node"]
|
|||||||
neon-build = "0.2.0"
|
neon-build = "0.2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
jsonpath_lib = "0.1.8"
|
jsonpath_lib = "0.1.9"
|
||||||
neon = "0.2.0"
|
neon = "0.2.0"
|
||||||
neon-serde = "0.1.1"
|
neon-serde = "0.1.1"
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
|
@ -4,13 +4,13 @@ extern crate neon;
|
|||||||
extern crate neon_serde;
|
extern crate neon_serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use jsonpath::filter::value_filter::JsonValueFilter;
|
use jsonpath::filter::value_filter::JsonValueFilter;
|
||||||
use jsonpath::parser::parser::{Node, NodeVisitor, Parser};
|
use jsonpath::parser::parser::{Node, NodeVisitor, Parser};
|
||||||
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
|
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
|
||||||
|
use jsonpath::Selector;
|
||||||
use neon::prelude::*;
|
use neon::prelude::*;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// `neon_serde::from_value` has very poor performance.
|
/// `neon_serde::from_value` has very poor performance.
|
||||||
@ -35,16 +35,20 @@ fn select_str(mut ctx: FunctionContext) -> JsResult<JsValue> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Compile {
|
pub struct CompileFn {
|
||||||
node: Node
|
node: Node
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Selector {
|
pub struct SelectorFn {
|
||||||
json: RefValueWrapper
|
json: RefValueWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SelectorCls {
|
||||||
|
selector: Selector
|
||||||
|
}
|
||||||
|
|
||||||
declare_types! {
|
declare_types! {
|
||||||
pub class JsCompile for Compile {
|
pub class JsCompileFn for CompileFn {
|
||||||
init(mut ctx) {
|
init(mut ctx) {
|
||||||
let path = ctx.argument::<JsString>(0)?.value();
|
let path = ctx.argument::<JsString>(0)?.value();
|
||||||
let mut parser = Parser::new(path.as_str());
|
let mut parser = Parser::new(path.as_str());
|
||||||
@ -54,7 +58,7 @@ declare_types! {
|
|||||||
Err(e) => panic!("{:?}", e)
|
Err(e) => panic!("{:?}", e)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Compile { node })
|
Ok(CompileFn { node })
|
||||||
}
|
}
|
||||||
|
|
||||||
method template(mut ctx) {
|
method template(mut ctx) {
|
||||||
@ -81,7 +85,7 @@ declare_types! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub class JsSelector for Selector {
|
pub class JsSelectorFn for SelectorFn {
|
||||||
init(mut ctx) {
|
init(mut ctx) {
|
||||||
let json_str = ctx.argument::<JsString>(0)?.value();
|
let json_str = ctx.argument::<JsString>(0)?.value();
|
||||||
let ref_value: RefValue = match serde_json::from_str(&json_str) {
|
let ref_value: RefValue = match serde_json::from_str(&json_str) {
|
||||||
@ -89,10 +93,10 @@ declare_types! {
|
|||||||
Err(e) => panic!("{:?}", e)
|
Err(e) => panic!("{:?}", e)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Selector { json: ref_value.into() })
|
Ok(SelectorFn { json: ref_value.into() })
|
||||||
}
|
}
|
||||||
|
|
||||||
method selector(mut ctx) {
|
method select(mut ctx) {
|
||||||
let this = ctx.this();
|
let this = ctx.this();
|
||||||
|
|
||||||
let json = {
|
let json = {
|
||||||
@ -117,9 +121,55 @@ declare_types! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub class JsSelector for SelectorCls {
|
||||||
|
init(mut _ctx) {
|
||||||
|
Ok(SelectorCls { selector: Selector::new() })
|
||||||
|
}
|
||||||
|
|
||||||
|
method path(mut ctx) {
|
||||||
|
let mut this = ctx.this();
|
||||||
|
|
||||||
|
let path = ctx.argument::<JsString>(0)?.value();
|
||||||
|
{
|
||||||
|
let guard = ctx.lock();
|
||||||
|
let mut this = this.borrow_mut(&guard);
|
||||||
|
let _ = this.selector.path(&path);
|
||||||
|
}
|
||||||
|
Ok(JsUndefined::new().upcast())
|
||||||
|
}
|
||||||
|
|
||||||
|
method value_from_str(mut ctx) {
|
||||||
|
let mut this = ctx.this();
|
||||||
|
|
||||||
|
let json_str = ctx.argument::<JsString>(0)?.value();
|
||||||
|
{
|
||||||
|
let guard = ctx.lock();
|
||||||
|
let mut this = this.borrow_mut(&guard);
|
||||||
|
let _ = this.selector.value_from_str(&json_str);
|
||||||
|
}
|
||||||
|
Ok(JsUndefined::new().upcast())
|
||||||
|
}
|
||||||
|
|
||||||
|
method select_to_str(mut ctx) {
|
||||||
|
let mut this = ctx.this();
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
let guard = ctx.lock();
|
||||||
|
let mut this = this.borrow_mut(&guard);
|
||||||
|
this.selector.select_to_str()
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(json_str) => Ok(JsString::new(&mut ctx, &json_str).upcast()),
|
||||||
|
Err(e) => panic!("{:?}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
register_module!(mut m, {
|
register_module!(mut m, {
|
||||||
m.export_class::<JsCompile>("Compile").expect("Compile class error");
|
m.export_class::<JsCompileFn>("CompileFn").expect("CompileFn class error");
|
||||||
|
m.export_class::<JsSelectorFn>("SelectorFn").expect("SelectorFn class error");
|
||||||
m.export_class::<JsSelector>("Selector").expect("Selector class error");
|
m.export_class::<JsSelector>("Selector").expect("Selector class error");
|
||||||
m.export_function("select", select)?;
|
m.export_function("select", select)?;
|
||||||
m.export_function("selectStr", select_str)?;
|
m.export_function("selectStr", select_str)?;
|
||||||
|
2
nodejs/package-lock.json
generated
2
nodejs/package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jsonpath-rs",
|
"name": "jsonpath-rs",
|
||||||
"version": "0.1.5",
|
"version": "0.1.7",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "jsonpath-rs",
|
"name": "jsonpath-rs",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"description": "It is JsonPath implementation. The core implementation is written in Rust",
|
"description": "It is JsonPath implementation. The core implementation is written in Rust",
|
||||||
"author": "Changseok Han <freestrings@gmail.com>",
|
"author": "Changseok Han <freestrings@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"jsonpath",
|
"jsonpath",
|
||||||
|
"rust-addon",
|
||||||
"rust-binding",
|
"rust-binding",
|
||||||
"rust",
|
"rust",
|
||||||
"rustlang",
|
"rustlang",
|
||||||
|
@ -1,5 +1,360 @@
|
|||||||
const jsonpath = require('../lib/index.js');
|
const jsonpath = require('../lib/index.js');
|
||||||
|
|
||||||
|
let jsonObj = {
|
||||||
|
"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 list = {
|
||||||
|
'$.store.book[*].author': [
|
||||||
|
"Nigel Rees",
|
||||||
|
"Evelyn Waugh",
|
||||||
|
"Herman Melville",
|
||||||
|
"J. R. R. Tolkien"
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..author':[
|
||||||
|
"Nigel Rees",
|
||||||
|
"Evelyn Waugh",
|
||||||
|
"Herman Melville",
|
||||||
|
"J. R. R. Tolkien"
|
||||||
|
],
|
||||||
|
|
||||||
|
'$.store.*': [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$.store..price':[
|
||||||
|
8.95,
|
||||||
|
12.99,
|
||||||
|
8.99,
|
||||||
|
22.99,
|
||||||
|
19.95
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..book[2]': [
|
||||||
|
{
|
||||||
|
"category": "fiction",
|
||||||
|
"author": "Herman Melville",
|
||||||
|
"title": "Moby Dick",
|
||||||
|
"isbn": "0-553-21311-3",
|
||||||
|
"price": 8.99
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..book[-2]': [
|
||||||
|
{
|
||||||
|
"category": "fiction",
|
||||||
|
"author": "Herman Melville",
|
||||||
|
"title": "Moby Dick",
|
||||||
|
"isbn": "0-553-21311-3",
|
||||||
|
"price": 8.99
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..book[0,1]': [
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..book[:2]': [
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..book[1:2]': [
|
||||||
|
{
|
||||||
|
"category": "fiction",
|
||||||
|
"author": "Evelyn Waugh",
|
||||||
|
"title": "Sword of Honour",
|
||||||
|
"price": 12.99
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..book[-2:]': [
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..book[2:]': [
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..book[?(@.isbn)]': [
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$.store.book[?(@.price < 10)]': [
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..*': [
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"reference",
|
||||||
|
"Nigel Rees",
|
||||||
|
"Sayings of the Century",
|
||||||
|
8.95,
|
||||||
|
"fiction",
|
||||||
|
"Evelyn Waugh",
|
||||||
|
"Sword of Honour",
|
||||||
|
12.99,
|
||||||
|
"fiction",
|
||||||
|
"Herman Melville",
|
||||||
|
"Moby Dick",
|
||||||
|
"0-553-21311-3",
|
||||||
|
8.99,
|
||||||
|
"fiction",
|
||||||
|
"J. R. R. Tolkien",
|
||||||
|
"The Lord of the Rings",
|
||||||
|
"0-395-19395-8",
|
||||||
|
22.99,
|
||||||
|
"red",
|
||||||
|
19.95
|
||||||
|
],
|
||||||
|
|
||||||
|
'$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]': [
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
describe('compile test', () => {
|
describe('compile test', () => {
|
||||||
it('basic', (done) => {
|
it('basic', (done) => {
|
||||||
let template = jsonpath.compile('$.a');
|
let template = jsonpath.compile('$.a');
|
||||||
@ -30,70 +385,218 @@ describe('select test', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('filter test', () => {
|
describe('filter test', () => {
|
||||||
it('complex filter1', (done) => {
|
|
||||||
let 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 target = [
|
function run(done, path, expected) {
|
||||||
{
|
let result = jsonpath.select(jsonObj, path);
|
||||||
category: 'fiction',
|
if (JSON.stringify(result) === JSON.stringify(expected)) {
|
||||||
author: 'Evelyn Waugh',
|
done();
|
||||||
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,
|
|
||||||
}]
|
|
||||||
;
|
|
||||||
|
|
||||||
let result = jsonpath.select(json, '$..book[?((@.price == 12.99 || $.store.bicycle.price < @.price) || @.category == "reference")]');
|
for( var i in list ) {
|
||||||
if (JSON.stringify(result) === JSON.stringify(target)) {
|
it(i, (done) => {
|
||||||
|
run (done, i, list[i]);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Selector test', () => {
|
||||||
|
it('basic selectTo', (done) => {
|
||||||
|
let result = new jsonpath.Selector().path('$.a').value({'a': 1}).selectTo();
|
||||||
|
if (result === 1) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('basic selectToStr', (done) => {
|
||||||
|
let result = new jsonpath.Selector().path('$.a').value({'a': 1}).selectToStr();
|
||||||
|
if (result === '1') {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('select', (done) => {
|
||||||
|
let selector = new jsonpath.Selector().value(jsonObj);
|
||||||
|
for(var i in list) {
|
||||||
|
if(JSON.stringify(list[i]) !== selector.path(i).selectToStr()) {
|
||||||
|
throw `fail: ${i}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('README test', () => {
|
||||||
|
it('jsonpath.Selector', (done) => {
|
||||||
|
let jsonObj = {
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let selector = new jsonpath.Selector().value(jsonObj);
|
||||||
|
|
||||||
|
{
|
||||||
|
let jsonObj = selector.path('$..[?(@.age >= 30)]').selectTo();
|
||||||
|
let resultObj = [{"name": "친구3", "age": 30}];
|
||||||
|
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
|
||||||
|
throw 'jsonpath.Selector: $..[?(@.age >= 30)]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let jsonObj = selector.path('$..[?(@.age == 20)]').selectTo();
|
||||||
|
let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}];
|
||||||
|
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
|
||||||
|
throw 'jsonpath.Selector: $..[?(@.age >= 20)]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let jsonObj = selector.value({"friends": [ {"name": "친구5", "age": 20} ]}).selectTo();
|
||||||
|
let resultObj = [{"name": "친구5", "age": 20}];
|
||||||
|
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
|
||||||
|
throw 'jsonpath.Selector: change value';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('jsonpath.select(json: string|object, jsonpath: string)', (done) => {
|
||||||
|
let jsonObj = {
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구1", "age": 20}
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
let selectAsString = jsonpath.select(JSON.stringify(jsonObj), '$..friends[0]');
|
||||||
|
let selectAsObj = jsonpath.select(jsonObj, '$..friends[0]');
|
||||||
|
|
||||||
|
if(
|
||||||
|
JSON.stringify(ret) !== JSON.stringify(selectAsString) ||
|
||||||
|
JSON.stringify(ret) !== JSON.stringify(selectAsObj)
|
||||||
|
) {
|
||||||
|
throw 'jsonpath.select(json: string|object, jsonpath: string)';
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('jsonpath.compile(jsonpath: string)', (done) => {
|
||||||
|
let template = jsonpath.compile('$..friends[0]');
|
||||||
|
|
||||||
|
let jsonObj = {
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구1", "age": 20}
|
||||||
|
];
|
||||||
|
|
||||||
|
let selectAsString = template(JSON.stringify(jsonObj));
|
||||||
|
let selectAsObj = template(jsonObj);
|
||||||
|
|
||||||
|
if(
|
||||||
|
JSON.stringify(ret) !== JSON.stringify(selectAsString) ||
|
||||||
|
JSON.stringify(ret) !== JSON.stringify(selectAsObj)
|
||||||
|
) {
|
||||||
|
throw 'jsonpath.compile(jsonpath: string) 1';
|
||||||
|
}
|
||||||
|
|
||||||
|
let jsonObj2 = {
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "Millicent Norman"},
|
||||||
|
{"name": "Vincent Cannon"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [ {"age": 30}, {"age": 40} ]
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret2 = [
|
||||||
|
{"age": 30},
|
||||||
|
{"name": "Millicent Norman"}
|
||||||
|
];
|
||||||
|
|
||||||
|
let selectAsString2 = template(JSON.stringify(jsonObj2));
|
||||||
|
let selectAsObj2 = template(jsonObj2);
|
||||||
|
|
||||||
|
if(
|
||||||
|
JSON.stringify(ret2) !== JSON.stringify(selectAsString2) ||
|
||||||
|
JSON.stringify(ret2) !== JSON.stringify(selectAsObj2)
|
||||||
|
) {
|
||||||
|
throw 'jsonpath.compile(jsonpath: string) 2';
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('jsonpath.selector(json: string|object)', (done) => {
|
||||||
|
let jsonObj = {
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret1 = [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구1", "age": 20}
|
||||||
|
];
|
||||||
|
|
||||||
|
let ret2 = [
|
||||||
|
{"name": "친구4"},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
];
|
||||||
|
|
||||||
|
let selector = jsonpath.selector(jsonObj);
|
||||||
|
let select1 = selector('$..friends[0]');
|
||||||
|
let select2 = selector('$..friends[1]');
|
||||||
|
|
||||||
|
if(
|
||||||
|
JSON.stringify(ret1) !== JSON.stringify(select1) ||
|
||||||
|
JSON.stringify(ret2) !== JSON.stringify(select2)
|
||||||
|
) {
|
||||||
|
throw 'jsonpath.selector(json: string|object)';
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
@ -6,8 +6,8 @@ use serde_json::Value;
|
|||||||
|
|
||||||
use filter::term::*;
|
use filter::term::*;
|
||||||
use filter::value_wrapper::*;
|
use filter::value_wrapper::*;
|
||||||
|
use parser::parser::{FilterToken, NodeVisitor, ParseToken};
|
||||||
use ref_value::model::*;
|
use ref_value::model::*;
|
||||||
use parser::parser::{ParseToken, FilterToken, NodeVisitor};
|
|
||||||
|
|
||||||
trait ArrayIndex {
|
trait ArrayIndex {
|
||||||
fn index(&self, v: &RefValueWrapper) -> usize;
|
fn index(&self, v: &RefValueWrapper) -> usize;
|
||||||
@ -56,14 +56,14 @@ pub enum ValueFilterKey {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ValueFilter {
|
pub struct ValueFilter {
|
||||||
vw: ValueWrapper,
|
val_wrapper: ValueWrapper,
|
||||||
last_key: Option<ValueFilterKey>,
|
last_key: Option<ValueFilterKey>,
|
||||||
filter_mode: bool,
|
filter_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueFilter {
|
impl ValueFilter {
|
||||||
pub fn new(v: RefValueWrapper, is_leaves: bool, filter_mode: bool) -> Self {
|
pub fn new(v: RefValueWrapper, is_leaves: bool, filter_mode: bool) -> Self {
|
||||||
ValueFilter { vw: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
|
ValueFilter { val_wrapper: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_to_value_vec<'a, I: Iterator<Item=&'a RefValueWrapper>>(iter: I) -> Vec<RefValueWrapper> {
|
fn iter_to_value_vec<'a, I: Iterator<Item=&'a RefValueWrapper>>(iter: I) -> Vec<RefValueWrapper> {
|
||||||
@ -130,11 +130,11 @@ impl ValueFilter {
|
|||||||
pub fn step_leaves_all(&mut self) -> &ValueWrapper {
|
pub fn step_leaves_all(&mut self) -> &ValueWrapper {
|
||||||
debug!("step_leaves_all");
|
debug!("step_leaves_all");
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
Self::collect_all(None, &self.vw.get_val(), &mut buf);
|
Self::collect_all(None, &self.val_wrapper.get_val(), &mut buf);
|
||||||
trace!("step_leaves_all - {:?}", buf);
|
trace!("step_leaves_all - {:?}", buf);
|
||||||
self.last_key = Some(ValueFilterKey::All);
|
self.last_key = Some(ValueFilterKey::All);
|
||||||
self.vw = ValueWrapper::new(RefValue::Array(buf).into(), true);
|
self.val_wrapper = ValueWrapper::new(RefValue::Array(buf).into(), true);
|
||||||
&self.vw
|
&self.val_wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_leaves_str(&mut self, key: &str) -> &ValueWrapper {
|
pub fn step_leaves_str(&mut self, key: &str) -> &ValueWrapper {
|
||||||
@ -144,17 +144,17 @@ impl ValueFilter {
|
|||||||
pub fn step_leaves_string(&mut self, key: &String) -> &ValueWrapper {
|
pub fn step_leaves_string(&mut self, key: &String) -> &ValueWrapper {
|
||||||
debug!("step_leaves_string");
|
debug!("step_leaves_string");
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
Self::collect_all(Some(key), &self.vw.get_val(), &mut buf);
|
Self::collect_all(Some(key), &self.val_wrapper.get_val(), &mut buf);
|
||||||
trace!("step_leaves_string - {:?}", buf);
|
trace!("step_leaves_string - {:?}", buf);
|
||||||
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
||||||
self.vw = ValueWrapper::new(RefValue::Array(buf).into(), true);
|
self.val_wrapper = ValueWrapper::new(RefValue::Array(buf).into(), true);
|
||||||
&self.vw
|
&self.val_wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_in_all(&mut self) -> &ValueWrapper {
|
pub fn step_in_all(&mut self) -> &ValueWrapper {
|
||||||
debug!("step_in_all");
|
debug!("step_in_all");
|
||||||
|
|
||||||
let vec = match self.vw.get_val().deref() {
|
let vec = match self.val_wrapper.get_val().deref() {
|
||||||
RefValue::Object(ref map) => {
|
RefValue::Object(ref map) => {
|
||||||
Self::iter_to_value_vec(map.values())
|
Self::iter_to_value_vec(map.values())
|
||||||
}
|
}
|
||||||
@ -162,25 +162,25 @@ impl ValueFilter {
|
|||||||
Self::iter_to_value_vec(list.iter())
|
Self::iter_to_value_vec(list.iter())
|
||||||
}
|
}
|
||||||
RefValue::Null => Vec::new(),
|
RefValue::Null => Vec::new(),
|
||||||
_ => vec![self.vw.get_val().clone()]
|
_ => vec![self.val_wrapper.get_val().clone()]
|
||||||
};
|
};
|
||||||
|
|
||||||
self.last_key = Some(ValueFilterKey::All);
|
self.last_key = Some(ValueFilterKey::All);
|
||||||
self.vw.replace(RefValue::Array(vec).into());
|
self.val_wrapper.replace(RefValue::Array(vec).into());
|
||||||
trace!("step_in_all - {:?}", self.vw.get_val());
|
trace!("step_in_all - {:?}", self.val_wrapper.get_val());
|
||||||
&self.vw
|
&self.val_wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_in_num(&mut self, key: &f64) -> &ValueWrapper {
|
pub fn step_in_num(&mut self, key: &f64) -> &ValueWrapper {
|
||||||
debug!("step_in_num");
|
debug!("step_in_num");
|
||||||
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
|
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
|
||||||
, self.vw.is_leaves()
|
, self.val_wrapper.is_leaves()
|
||||||
, self.filter_mode
|
, self.filter_mode
|
||||||
, self.vw.get_val());
|
, self.val_wrapper.get_val());
|
||||||
|
|
||||||
let v = if self.vw.is_leaves() {
|
let v = if self.val_wrapper.is_leaves() {
|
||||||
let filter_mode = self.filter_mode;
|
let filter_mode = self.filter_mode;
|
||||||
match self.vw.get_val().deref() {
|
match self.val_wrapper.get_val().deref() {
|
||||||
RefValue::Array(ref vec) => {
|
RefValue::Array(ref vec) => {
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
for v in vec {
|
for v in vec {
|
||||||
@ -191,16 +191,16 @@ impl ValueFilter {
|
|||||||
}
|
}
|
||||||
RefValue::Array(ret).into()
|
RefValue::Array(ret).into()
|
||||||
}
|
}
|
||||||
_ => key.take_value(&self.vw.get_val())
|
_ => key.take_value(&self.val_wrapper.get_val())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
key.take_value(&self.vw.get_val())
|
key.take_value(&self.val_wrapper.get_val())
|
||||||
};
|
};
|
||||||
|
|
||||||
self.last_key = Some(ValueFilterKey::Num(key.index(&v)));
|
self.last_key = Some(ValueFilterKey::Num(key.index(&v)));
|
||||||
self.vw.replace(v);
|
self.val_wrapper.replace(v);
|
||||||
trace!("step_in_num - after: {:?}", self.vw.get_val());
|
trace!("step_in_num - after: {:?}", self.val_wrapper.get_val());
|
||||||
&self.vw
|
&self.val_wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_in_str(&mut self, key: &str) -> &ValueWrapper {
|
pub fn step_in_str(&mut self, key: &str) -> &ValueWrapper {
|
||||||
@ -210,13 +210,13 @@ impl ValueFilter {
|
|||||||
pub fn step_in_string(&mut self, key: &String) -> &ValueWrapper {
|
pub fn step_in_string(&mut self, key: &String) -> &ValueWrapper {
|
||||||
debug!("step_in_string");
|
debug!("step_in_string");
|
||||||
trace!("step_in_string - before: {},{},{:?}"
|
trace!("step_in_string - before: {},{},{:?}"
|
||||||
, self.vw.is_leaves()
|
, self.val_wrapper.is_leaves()
|
||||||
, self.filter_mode
|
, self.filter_mode
|
||||||
, self.vw.get_val());
|
, self.val_wrapper.get_val());
|
||||||
|
|
||||||
let filter_mode = self.filter_mode;
|
let filter_mode = self.filter_mode;
|
||||||
let is_leaves = self.vw.is_leaves();
|
let is_leaves = self.val_wrapper.is_leaves();
|
||||||
let val = match self.vw.get_val().deref() {
|
let val = match self.val_wrapper.get_val().deref() {
|
||||||
RefValue::Array(ref vec) if is_leaves => {
|
RefValue::Array(ref vec) if is_leaves => {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
for mut v in vec {
|
for mut v in vec {
|
||||||
@ -230,6 +230,11 @@ impl ValueFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf.append(&mut ret);
|
buf.append(&mut ret);
|
||||||
|
} else if v.is_object() {
|
||||||
|
let nested_wrapper = Self::get_nested_object(v, key, filter_mode);
|
||||||
|
if !nested_wrapper.is_null() {
|
||||||
|
buf.push(nested_wrapper.clone());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
match v.get(key.clone()) {
|
match v.get(key.clone()) {
|
||||||
Some(v) => buf.push(v.clone()),
|
Some(v) => buf.push(v.clone()),
|
||||||
@ -251,7 +256,7 @@ impl ValueFilter {
|
|||||||
RefValue::Array(ret).into()
|
RefValue::Array(ret).into()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
match self.vw.get_val().get(key.clone()) {
|
match self.val_wrapper.get_val().get(key.clone()) {
|
||||||
Some(v) => v.clone(),
|
Some(v) => v.clone(),
|
||||||
_ => RefValue::Null.into()
|
_ => RefValue::Null.into()
|
||||||
}
|
}
|
||||||
@ -259,12 +264,12 @@ impl ValueFilter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
self.last_key = Some(ValueFilterKey::String(key.clone()));
|
||||||
self.vw.replace(val);
|
self.val_wrapper.replace(val);
|
||||||
trace!("step_in_string - after: {},{},{:?}"
|
trace!("step_in_string - after: {},{},{:?}"
|
||||||
, self.vw.is_leaves()
|
, self.val_wrapper.is_leaves()
|
||||||
, self.filter_mode
|
, self.filter_mode
|
||||||
, self.vw.get_val());
|
, self.val_wrapper.get_val());
|
||||||
&self.vw
|
&self.val_wrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +308,7 @@ impl JsonValueFilter {
|
|||||||
if from_current {
|
if from_current {
|
||||||
self.filter_stack.last()
|
self.filter_stack.last()
|
||||||
.map(|vf| {
|
.map(|vf| {
|
||||||
ValueFilter::new(vf.vw.get_val().clone(), vf.vw.is_leaves(), from_current)
|
ValueFilter::new(vf.val_wrapper.get_val().clone(), vf.val_wrapper.is_leaves(), from_current)
|
||||||
})
|
})
|
||||||
.and_then(|vf| {
|
.and_then(|vf| {
|
||||||
Some(self.filter_stack.push(vf))
|
Some(self.filter_stack.push(vf))
|
||||||
@ -321,13 +326,13 @@ impl JsonValueFilter {
|
|||||||
} else {
|
} else {
|
||||||
match self.filter_stack.last_mut() {
|
match self.filter_stack.last_mut() {
|
||||||
Some(vf) => {
|
Some(vf) => {
|
||||||
vf.vw.set_leaves(is_leaves);
|
vf.val_wrapper.set_leaves(is_leaves);
|
||||||
if v.is_null() {
|
if v.is_null() {
|
||||||
vf.vw.replace(v);
|
vf.val_wrapper.replace(v);
|
||||||
} else if v.is_array() && v.as_array().unwrap().is_empty() {
|
} else if v.is_array() && v.as_array().unwrap().is_empty() {
|
||||||
vf.vw.replace(RefValue::Null.into());
|
vf.val_wrapper.replace(RefValue::Null.into());
|
||||||
} else if vf.vw.is_array() {
|
} else if vf.val_wrapper.is_array() {
|
||||||
vf.vw.replace(v);
|
vf.val_wrapper.replace(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -337,14 +342,14 @@ impl JsonValueFilter {
|
|||||||
|
|
||||||
pub fn into_value(&self) -> Value {
|
pub fn into_value(&self) -> Value {
|
||||||
match self.filter_stack.last() {
|
match self.filter_stack.last() {
|
||||||
Some(v) => v.vw.into_value(),
|
Some(v) => v.val_wrapper.into_value(),
|
||||||
_ => Value::Null
|
_ => Value::Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_value(&mut self) -> RefValueWrapper {
|
pub fn take_value(&mut self) -> RefValueWrapper {
|
||||||
match self.filter_stack.last_mut() {
|
match self.filter_stack.last_mut() {
|
||||||
Some(v) => v.vw.get_val().clone(),
|
Some(v) => v.val_wrapper.get_val().clone(),
|
||||||
_ => RefValue::Null.into()
|
_ => RefValue::Null.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,9 +358,9 @@ impl JsonValueFilter {
|
|||||||
self.token_stack.pop();
|
self.token_stack.pop();
|
||||||
|
|
||||||
match self.filter_stack.last_mut() {
|
match self.filter_stack.last_mut() {
|
||||||
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
|
Some(ref mut vf) if vf.val_wrapper.is_array() && vf.val_wrapper.is_leaves() => {
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
if let RefValue::Array(val) = vf.vw.get_val().deref() {
|
if let RefValue::Array(val) = vf.val_wrapper.get_val().deref() {
|
||||||
for mut v in val {
|
for mut v in val {
|
||||||
for i in &indices {
|
for i in &indices {
|
||||||
let v = i.take_value(v);
|
let v = i.take_value(v);
|
||||||
@ -365,17 +370,17 @@ impl JsonValueFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vf.vw.replace(RefValue::Array(ret).into());
|
vf.val_wrapper.replace(RefValue::Array(ret).into());
|
||||||
}
|
}
|
||||||
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
|
Some(ref mut vf) if vf.val_wrapper.is_array() && !vf.val_wrapper.is_leaves() => {
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
for i in indices {
|
for i in indices {
|
||||||
let wrapper = i.take_value(&vf.vw.get_val());
|
let wrapper = i.take_value(&vf.val_wrapper.get_val());
|
||||||
if !wrapper.is_null() {
|
if !wrapper.is_null() {
|
||||||
ret.push(wrapper.clone());
|
ret.push(wrapper.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vf.vw.replace(RefValue::Array(ret).into());
|
vf.val_wrapper.replace(RefValue::Array(ret).into());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -413,21 +418,21 @@ impl JsonValueFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match self.filter_stack.last_mut() {
|
match self.filter_stack.last_mut() {
|
||||||
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
|
Some(ref mut vf) if vf.val_wrapper.is_array() && vf.val_wrapper.is_leaves() => {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
if let RefValue::Array(vec) = vf.vw.get_val().deref() {
|
if let RefValue::Array(vec) = vf.val_wrapper.get_val().deref() {
|
||||||
for mut v in vec {
|
for mut v in vec {
|
||||||
let (from, to) = _from_to(from, to, v);
|
let (from, to) = _from_to(from, to, v);
|
||||||
let mut v: Vec<RefValueWrapper> = _range(from, to, v);
|
let mut v: Vec<RefValueWrapper> = _range(from, to, v);
|
||||||
buf.append(&mut v);
|
buf.append(&mut v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vf.vw.replace(RefValue::Array(buf).into());
|
vf.val_wrapper.replace(RefValue::Array(buf).into());
|
||||||
}
|
}
|
||||||
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
|
Some(ref mut vf) if vf.val_wrapper.is_array() && !vf.val_wrapper.is_leaves() => {
|
||||||
let (from, to) = _from_to(from, to, &vf.vw.get_val());
|
let (from, to) = _from_to(from, to, &vf.val_wrapper.get_val());
|
||||||
let vec: Vec<RefValueWrapper> = _range(from, to, vf.vw.get_val());
|
let vec: Vec<RefValueWrapper> = _range(from, to, vf.val_wrapper.get_val());
|
||||||
vf.vw.replace(RefValue::Array(vec).into());
|
vf.val_wrapper.replace(RefValue::Array(vec).into());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -491,13 +496,13 @@ impl JsonValueFilter {
|
|||||||
_ => {
|
_ => {
|
||||||
match self.filter_stack.pop() {
|
match self.filter_stack.pop() {
|
||||||
Some(mut vf) => {
|
Some(mut vf) => {
|
||||||
let is_leaves = vf.vw.is_leaves();
|
let is_leaves = vf.val_wrapper.is_leaves();
|
||||||
match vf.vw.get_val().deref() {
|
match vf.val_wrapper.get_val().deref() {
|
||||||
RefValue::Null | RefValue::Bool(false) => {
|
RefValue::Null | RefValue::Bool(false) => {
|
||||||
self.replace_filter_stack(RefValue::Null.into(), is_leaves);
|
self.replace_filter_stack(RefValue::Null.into(), is_leaves);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.replace_filter_stack(vf.vw.get_val().clone(), is_leaves);
|
self.replace_filter_stack(vf.val_wrapper.get_val().clone(), is_leaves);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -548,8 +553,13 @@ impl NodeVisitor for JsonValueFilter {
|
|||||||
self.push_value_filter(ParseToken::Relative == token);
|
self.push_value_filter(ParseToken::Relative == token);
|
||||||
}
|
}
|
||||||
ParseToken::In
|
ParseToken::In
|
||||||
| ParseToken::Leaves
|
| ParseToken::Leaves => {
|
||||||
| ParseToken::Array => {
|
self.token_stack.push(token);
|
||||||
|
}
|
||||||
|
ParseToken::Array => {
|
||||||
|
if let Some(ParseToken::Leaves) = self.token_stack.last() {
|
||||||
|
self.token_all();
|
||||||
|
}
|
||||||
self.token_stack.push(token);
|
self.token_stack.push(token);
|
||||||
}
|
}
|
||||||
ParseToken::ArrayEof => {
|
ParseToken::ArrayEof => {
|
||||||
@ -593,7 +603,7 @@ impl NodeVisitor for JsonValueFilter {
|
|||||||
if self.token_stack.is_empty() && self.filter_stack.len() > 1 {
|
if self.token_stack.is_empty() && self.filter_stack.len() > 1 {
|
||||||
match self.filter_stack.pop() {
|
match self.filter_stack.pop() {
|
||||||
Some(vf) => {
|
Some(vf) => {
|
||||||
self.term_stack.push(TermContext::Json(vf.last_key, vf.vw));
|
self.term_stack.push(TermContext::Json(vf.last_key, vf.val_wrapper));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -79,15 +79,15 @@ impl ValueWrapper {
|
|||||||
|
|
||||||
match self.val.deref() {
|
match self.val.deref() {
|
||||||
RefValue::Array(vec) => {
|
RefValue::Array(vec) => {
|
||||||
let mut ret = Vec::new();
|
let mut set = IndexSet::new();
|
||||||
for v in vec {
|
for v in vec {
|
||||||
if _filter_with_object(v, key, |vv| {
|
if _filter_with_object(v, key, |vv| {
|
||||||
Self::cmp_with_term(vv, et, cmp, false, reverse)
|
Self::cmp_with_term(vv, et, cmp, false, reverse)
|
||||||
}) {
|
}) {
|
||||||
ret.push(v.clone());
|
set.insert(v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let ret = set.into_iter().collect();
|
||||||
Some(ValueWrapper::new(RefValue::Array(ret).into(), false))
|
Some(ValueWrapper::new(RefValue::Array(ret).into(), false))
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None
|
||||||
@ -109,12 +109,13 @@ impl ValueWrapper {
|
|||||||
_ => {
|
_ => {
|
||||||
match &(*self.val) {
|
match &(*self.val) {
|
||||||
RefValue::Array(vec) => {
|
RefValue::Array(vec) => {
|
||||||
let mut ret = Vec::new();
|
let mut set = IndexSet::new();
|
||||||
for v in vec {
|
for v in vec {
|
||||||
if Self::cmp_with_term(v, et, &cmp, false, reverse) {
|
if Self::cmp_with_term(v, et, &cmp, false, reverse) {
|
||||||
ret.push(v.clone());
|
set.insert(v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let ret = set.into_iter().collect();
|
||||||
ValueWrapper::new(RefValue::Array(ret).into(), false)
|
ValueWrapper::new(RefValue::Array(ret).into(), false)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
94
src/lib.rs
94
src/lib.rs
@ -158,6 +158,7 @@
|
|||||||
//! assert_eq!(ret, json);
|
//! assert_eq!(ret, json);
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
extern crate core;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate indexmap;
|
extern crate indexmap;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -166,40 +167,23 @@ extern crate log;
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
use std::error::Error;
|
use core::borrow::BorrowMut;
|
||||||
use std::ops::Deref;
|
|
||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use filter::value_filter::JsonValueFilter;
|
|
||||||
use parser::parser::{NodeVisitor, Parser};
|
|
||||||
use ref_value::model::RefValueWrapper;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod filter;
|
pub mod filter;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod ref_value;
|
pub mod ref_value;
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod select;
|
||||||
|
|
||||||
fn query_from_str(json: &str, path: &str) -> result::Result<JsonValueFilter, String> {
|
pub use select::Selector;
|
||||||
let mut jf = JsonValueFilter::new(json)?;
|
|
||||||
let mut parser = Parser::new(path);
|
|
||||||
parser.parse(&mut jf)?;
|
|
||||||
Ok(jf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_from_json_wrapper(json_wrapper: RefValueWrapper, path: &str) -> result::Result<JsonValueFilter, String> {
|
/// It is a high-order function. it compile a JsonPath and then returns a function. this return-function can be reused for different JsonObjects.
|
||||||
let mut jf = JsonValueFilter::new_from_value(json_wrapper);
|
|
||||||
let mut parser = Parser::new(path);
|
|
||||||
parser.parse(&mut jf)?;
|
|
||||||
Ok(jf)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// It is a highorder function that compile a JsonPath then returns a function.
|
|
||||||
///
|
|
||||||
/// this return function can be reused for different JsonObjects.
|
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate jsonpath_lib as jsonpath;
|
/// extern crate jsonpath_lib as jsonpath;
|
||||||
@ -227,23 +211,17 @@ fn query_from_json_wrapper(json_wrapper: RefValueWrapper, path: &str) -> result:
|
|||||||
/// assert_eq!(json, ret);
|
/// assert_eq!(json, ret);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result<Value, String> + 'a {
|
pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result<Value, String> + 'a {
|
||||||
let mut parser = Parser::new(path);
|
let mut selector = select::Selector::new();
|
||||||
let node = parser.compile();
|
let _ = selector.path(path);
|
||||||
|
let mut selector = Box::new(selector);
|
||||||
move |json| {
|
move |json| {
|
||||||
match &node {
|
let s: &mut select::Selector = selector.borrow_mut();
|
||||||
Ok(n) => {
|
let _ = s.value(json.into());
|
||||||
let mut jf = JsonValueFilter::new_from_value(json.into());
|
s.select_to_value()
|
||||||
jf.visit(n.clone());
|
|
||||||
Ok((&jf.take_value()).into())
|
|
||||||
}
|
|
||||||
Err(e) => Err(e.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// It returns highorder function that return a function.
|
/// It is a high-order function that return a function. this return-function has a jsonpath as argument and return a serde_json::value::Value. so you can use different JsonPath for one JsonObject.
|
||||||
///
|
|
||||||
/// this function has a jsonpath as argument and return a serde_json::value::Value. so you can use different JsonPath for one JsonObject.
|
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate jsonpath_lib as jsonpath;
|
/// extern crate jsonpath_lib as jsonpath;
|
||||||
@ -277,17 +255,17 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result<Value,
|
|||||||
/// ]);
|
/// ]);
|
||||||
/// assert_eq!(json, ret);
|
/// assert_eq!(json, ret);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn selector(json: &Value) -> impl FnMut(&str) -> result::Result<Value, String> {
|
pub fn selector<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value, String> {
|
||||||
let wrapper: RefValueWrapper = json.into();
|
let mut selector = select::Selector::new();
|
||||||
move |path: &str| {
|
let _ = selector.value(json.into());
|
||||||
let mut jf = query_from_json_wrapper(wrapper.clone(), path)?;
|
let mut selector = Box::new(selector);
|
||||||
Ok((&jf.take_value()).into())
|
move |path: &'a str| {
|
||||||
|
let s: &mut select::Selector = selector.borrow_mut();
|
||||||
|
s.path(path)?.select_to_value()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// It returns highorder function that returns a function.
|
/// It is a high-order function that returns a function. this return-function has a jsonpath as argument and return a serde::Deserialize. so you can use different JsonPath for one JsonObject.
|
||||||
///
|
|
||||||
/// this function has a jsonpath as argument and return a serde::Deserialize. so you can use different JsonPath for one JsonObject.
|
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate jsonpath_lib as jsonpath;
|
/// extern crate jsonpath_lib as jsonpath;
|
||||||
@ -331,19 +309,19 @@ pub fn selector(json: &Value) -> impl FnMut(&str) -> result::Result<Value, Strin
|
|||||||
/// assert_eq!(json, ret);
|
/// assert_eq!(json, ret);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn selector_as<T: serde::de::DeserializeOwned>(json: &Value) -> impl FnMut(&str) -> result::Result<T, String> {
|
pub fn selector_as<T: serde::de::DeserializeOwned>(json: &Value) -> impl FnMut(&str) -> result::Result<T, String> {
|
||||||
let wrapper: RefValueWrapper = json.into();
|
let mut selector = select::Selector::new();
|
||||||
|
let _ = selector.value(json.into());
|
||||||
move |path: &str| {
|
move |path: &str| {
|
||||||
let mut jf = query_from_json_wrapper(wrapper.clone(), path)?;
|
selector.path(path)?.select_to()
|
||||||
T::deserialize(jf.take_value().deref()).map_err(|e| format!("{:?}", e))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated(since = "0.1.4", note = "Please use the selector function instead")]
|
#[deprecated(since = "0.1.4", note = "Please use the selector function instead")]
|
||||||
pub fn reader(json: &Value) -> impl FnMut(&str) -> result::Result<Value, String> {
|
pub fn reader<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value, String> {
|
||||||
selector(json)
|
selector(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Select a JsonObject. it return a serde_json::value::Value.
|
/// This function compile a jsonpath everytime and it convert `serde_json's Value` to `jsonpath's RefValue` everytime and then it return a `serde_json::value::Value`.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate jsonpath_lib as jsonpath;
|
/// extern crate jsonpath_lib as jsonpath;
|
||||||
@ -370,8 +348,8 @@ pub fn reader(json: &Value) -> impl FnMut(&str) -> result::Result<Value, String>
|
|||||||
/// assert_eq!(json, ret);
|
/// assert_eq!(json, ret);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn select(json: &Value, path: &str) -> result::Result<Value, String> {
|
pub fn select(json: &Value, path: &str) -> result::Result<Value, String> {
|
||||||
let mut jf = query_from_json_wrapper(json.into(), path)?;
|
let mut selector = select::Selector::new();
|
||||||
Ok((&jf.take_value()).into())
|
selector.path(path)?.value(json.into())?.select_to_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated(since = "0.1.4", note = "Please use the select function instead")]
|
#[deprecated(since = "0.1.4", note = "Please use the select function instead")]
|
||||||
@ -384,7 +362,7 @@ pub fn select_str(json: &str, path: &str) -> result::Result<String, String> {
|
|||||||
select_as_str(json, path)
|
select_as_str(json, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Select a JsonObject. it return a JsonObject as String.
|
/// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a json string.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate jsonpath_lib as jsonpath;
|
/// extern crate jsonpath_lib as jsonpath;
|
||||||
@ -408,11 +386,13 @@ pub fn select_str(json: &str, path: &str) -> result::Result<String, String> {
|
|||||||
/// assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
|
/// assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn select_as_str(json: &str, path: &str) -> result::Result<String, String> {
|
pub fn select_as_str(json: &str, path: &str) -> result::Result<String, String> {
|
||||||
let mut jf = query_from_str(json, path)?;
|
select::Selector::new()
|
||||||
serde_json::to_string(&jf.take_value().deref()).map_err(|e| e.description().to_string())
|
.path(path)?
|
||||||
|
.value_from_str(json)?
|
||||||
|
.select_to_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Select a JsonObject. it return a deserialized instance of type `T`
|
/// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a deserialized-instance of type `T`.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate jsonpath_lib as jsonpath;
|
/// extern crate jsonpath_lib as jsonpath;
|
||||||
@ -451,6 +431,8 @@ pub fn select_as_str(json: &str, path: &str) -> result::Result<String, String> {
|
|||||||
/// assert_eq!(person, ret);
|
/// assert_eq!(person, ret);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn select_as<T: serde::de::DeserializeOwned>(json: &str, path: &str) -> result::Result<T, String> {
|
pub fn select_as<T: serde::de::DeserializeOwned>(json: &str, path: &str) -> result::Result<T, String> {
|
||||||
let mut jf = query_from_str(json, path)?;
|
select::Selector::new()
|
||||||
T::deserialize(jf.take_value().deref()).map_err(|e| e.description().to_string())
|
.path(path)?
|
||||||
|
.value_from_str(json)?
|
||||||
|
.select_to()
|
||||||
}
|
}
|
@ -245,6 +245,15 @@ impl Into<RefValueWrapper> for RefValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<RefValue> for &Value {
|
||||||
|
fn into(self) -> RefValue {
|
||||||
|
match self.serialize(super::ser::Serializer) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => panic!("Error Value into RefValue: {:?}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Into<RefValueWrapper> for &Value {
|
impl Into<RefValueWrapper> for &Value {
|
||||||
fn into(self) -> RefValueWrapper {
|
fn into(self) -> RefValueWrapper {
|
||||||
match self.serialize(super::ser::Serializer) {
|
match self.serialize(super::ser::Serializer) {
|
||||||
|
152
src/select/mod.rs
Normal file
152
src/select/mod.rs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
use std::result;
|
||||||
|
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use super::filter::value_filter::*;
|
||||||
|
use super::parser::parser::*;
|
||||||
|
use super::ref_value::model::*;
|
||||||
|
|
||||||
|
/// Utility. Functions like jsonpath::selector or jsonpath::compile are also implemented using this structure.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate jsonpath_lib as jsonpath;
|
||||||
|
/// extern crate serde;
|
||||||
|
/// extern crate serde_json;
|
||||||
|
///
|
||||||
|
/// use serde::{Deserialize, Serialize};
|
||||||
|
/// use serde_json::Value;
|
||||||
|
///
|
||||||
|
/// use jsonpath::Selector;
|
||||||
|
///
|
||||||
|
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
/// struct Person {
|
||||||
|
/// name: String,
|
||||||
|
/// age: u8,
|
||||||
|
/// phone: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn input_str() -> &'static str {
|
||||||
|
/// r#"[
|
||||||
|
/// {
|
||||||
|
/// "name": "이름1",
|
||||||
|
/// "age": 40,
|
||||||
|
/// "phone": "+33 12341234"
|
||||||
|
/// },
|
||||||
|
/// {
|
||||||
|
/// "name": "이름2",
|
||||||
|
/// "age": 42,
|
||||||
|
/// "phone": "++44 12341234"
|
||||||
|
/// }
|
||||||
|
/// ]"#
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn input_json() -> Value {
|
||||||
|
/// serde_json::from_str(input_str()).unwrap()
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn input_person() -> Vec<Person> {
|
||||||
|
/// serde_json::from_str(input_str()).unwrap()
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// let mut selector = Selector::new();
|
||||||
|
///
|
||||||
|
/// let result = selector
|
||||||
|
/// .path("$..[?(@.age > 40)]").unwrap()
|
||||||
|
/// .value_from_str(input_str()).unwrap()
|
||||||
|
/// .select_to_value().unwrap();
|
||||||
|
/// assert_eq!(input_json()[1], result[0]);
|
||||||
|
///
|
||||||
|
/// let result = selector.select_to_str().unwrap();
|
||||||
|
/// assert_eq!(serde_json::to_string(&vec![&input_json()[1].clone()]).unwrap(), result);
|
||||||
|
///
|
||||||
|
/// let result = selector.select_to::<Vec<Person>>().unwrap();
|
||||||
|
/// assert_eq!(input_person()[1], result[0]);
|
||||||
|
///
|
||||||
|
/// let _ = selector.path("$..[?(@.age == 40)]");
|
||||||
|
///
|
||||||
|
/// let result = selector.select_to_value().unwrap();
|
||||||
|
/// assert_eq!(input_json()[0], result[0]);
|
||||||
|
///
|
||||||
|
/// let result = selector.select_to_str().unwrap();
|
||||||
|
/// assert_eq!(serde_json::to_string(&vec![&input_json()[0].clone()]).unwrap(), result);
|
||||||
|
///
|
||||||
|
/// let result = selector.select_to::<Vec<Person>>().unwrap();
|
||||||
|
/// assert_eq!(input_person()[0], result[0]);
|
||||||
|
/// ```
|
||||||
|
pub struct Selector {
|
||||||
|
pub(crate) node: Option<Node>,
|
||||||
|
pub(crate) value: Option<RefValueWrapper>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Selector {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Selector { node: None, value: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(&mut self, path: &str) -> result::Result<&mut Self, String> {
|
||||||
|
let mut parser = Parser::new(path);
|
||||||
|
self.node = Some(parser.compile()?);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&mut self, ref_value: RefValue) -> result::Result<&mut Self, String> {
|
||||||
|
self.value = Some(ref_value.into());
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_from(&mut self, serializable: &impl serde::ser::Serialize) -> result::Result<&mut Self, String> {
|
||||||
|
let ref_value: RefValue = serializable
|
||||||
|
.serialize(super::ref_value::ser::Serializer)
|
||||||
|
.map_err(|e| format!("{:?}", e))?;
|
||||||
|
self.value(ref_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_from_str(&mut self, json_str: &str) -> result::Result<&mut Self, String> {
|
||||||
|
let ref_value: RefValue = serde_json::from_str(json_str)
|
||||||
|
.map_err(|e| format!("{:?}", e))?;
|
||||||
|
self.value(ref_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jf(&mut self) -> result::Result<JsonValueFilter, String> {
|
||||||
|
match &self.value {
|
||||||
|
Some(v) => Ok(JsonValueFilter::new_from_value(v.clone())),
|
||||||
|
_ => return Err("Value is empty".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_to_str(&mut self) -> result::Result<String, String> {
|
||||||
|
let mut jf = self.jf()?;
|
||||||
|
|
||||||
|
match &mut self.node {
|
||||||
|
Some(node) => {
|
||||||
|
jf.visit(node.clone());
|
||||||
|
return serde_json::to_string(jf.take_value().deref()).map_err(|e| format!("{:?}", e));
|
||||||
|
}
|
||||||
|
_ => return Err("Path is empty".to_owned())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_to_value(&mut self) -> result::Result<Value, String> {
|
||||||
|
let mut jf = self.jf()?;
|
||||||
|
match &mut self.node {
|
||||||
|
Some(node) => {
|
||||||
|
jf.visit(node.clone());
|
||||||
|
Ok((&jf.take_value()).into())
|
||||||
|
}
|
||||||
|
_ => Err("Path is empty".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_to<T: serde::de::DeserializeOwned>(&mut self) -> result::Result<T, String> {
|
||||||
|
let mut jf = self.jf()?;
|
||||||
|
match &mut self.node {
|
||||||
|
Some(node) => {
|
||||||
|
jf.visit(node.clone());
|
||||||
|
T::deserialize(jf.take_value().deref()).map_err(|e| format!("{:?}", e))
|
||||||
|
}
|
||||||
|
_ => Err("Path is empty".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -201,6 +201,36 @@ fn op_default() {
|
|||||||
let jf = do_filter("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
|
let jf = do_filter("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
|
||||||
let friends = json!([12.99]);
|
let friends = json!([12.99]);
|
||||||
assert_eq!(friends, jf.into_value());
|
assert_eq!(friends, jf.into_value());
|
||||||
|
|
||||||
|
let ref value = json!([
|
||||||
|
{ "name": "이름1", "age": 40, "phone": "+33 12341234" },
|
||||||
|
{ "name": "이름2", "age": 42, "phone": "++44 12341234" }
|
||||||
|
]);
|
||||||
|
let mut jf = JsonValueFilter::new_from_value(value.into());
|
||||||
|
let mut parser = Parser::new("$..[?(@.age > 40)]");
|
||||||
|
parser.parse(&mut jf).unwrap();
|
||||||
|
let friends = json!([
|
||||||
|
{ "name" : "이름2", "age" : 42, "phone" : "++44 12341234" }
|
||||||
|
]);
|
||||||
|
assert_eq!(friends, jf.into_value());
|
||||||
|
|
||||||
|
let ref value = json!({
|
||||||
|
"school": {
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구1", "age": 20},
|
||||||
|
{"name": "친구2", "age": 20}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"friends": [
|
||||||
|
{"name": "친구3", "age": 30},
|
||||||
|
{"name": "친구4"}
|
||||||
|
]});
|
||||||
|
let mut jf = JsonValueFilter::new_from_value(value.into());
|
||||||
|
let mut parser = Parser::new("$..[?(@.age >= 30)]");
|
||||||
|
parser.parse(&mut jf).unwrap();
|
||||||
|
let friends = json!([{ "name" : "친구3", "age" : 30 }]);
|
||||||
|
assert_eq!(friends, jf.into_value());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
92
tests/selector.rs
Normal file
92
tests/selector.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
extern crate jsonpath_lib as jsonpath;
|
||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use jsonpath::Selector;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Person {
|
||||||
|
name: String,
|
||||||
|
age: u8,
|
||||||
|
phone: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_str() -> &'static str {
|
||||||
|
r#"[
|
||||||
|
{
|
||||||
|
"name": "이름1",
|
||||||
|
"age": 40,
|
||||||
|
"phone": "+33 12341234"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "이름2",
|
||||||
|
"age": 42,
|
||||||
|
"phone": "++44 12341234"
|
||||||
|
}
|
||||||
|
]"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_json() -> Value {
|
||||||
|
serde_json::from_str(input_str()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_person() -> Vec<Person> {
|
||||||
|
serde_json::from_str(input_str()).unwrap()
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn selector_value_from() {
|
||||||
|
let result = Selector::new()
|
||||||
|
.path("$..[?(@.age > 40)]").unwrap()
|
||||||
|
.value_from(&input_person()).unwrap()
|
||||||
|
.select_to::<Vec<Person>>().unwrap();
|
||||||
|
assert_eq!(input_person()[1], result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn selector_value() {
|
||||||
|
let result = Selector::new()
|
||||||
|
.path("$..[?(@.age > 40)]").unwrap()
|
||||||
|
.value((&input_json()).into()).unwrap()
|
||||||
|
.select_to_value().unwrap();
|
||||||
|
assert_eq!(input_json()[1], result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn selector_value_from_str() {
|
||||||
|
let result = Selector::new()
|
||||||
|
.path("$..[?(@.age > 40)]").unwrap()
|
||||||
|
.value_from_str(input_str()).unwrap()
|
||||||
|
.select_to_value().unwrap();
|
||||||
|
assert_eq!(input_json()[1], result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn selector_select_to() {
|
||||||
|
let mut selector = Selector::new();
|
||||||
|
|
||||||
|
let result = selector
|
||||||
|
.path("$..[?(@.age > 40)]").unwrap()
|
||||||
|
.value_from_str(input_str()).unwrap()
|
||||||
|
.select_to_value().unwrap();
|
||||||
|
assert_eq!(input_json()[1], result[0]);
|
||||||
|
|
||||||
|
let result = selector.select_to_str().unwrap();
|
||||||
|
assert_eq!(serde_json::to_string(&vec![&input_json()[1].clone()]).unwrap(), result);
|
||||||
|
|
||||||
|
let result = selector.select_to::<Vec<Person>>().unwrap();
|
||||||
|
assert_eq!(input_person()[1], result[0]);
|
||||||
|
|
||||||
|
let _ = selector.path("$..[?(@.age == 40)]");
|
||||||
|
|
||||||
|
let result = selector.select_to_value().unwrap();
|
||||||
|
assert_eq!(input_json()[0], result[0]);
|
||||||
|
|
||||||
|
let result = selector.select_to_str().unwrap();
|
||||||
|
assert_eq!(serde_json::to_string(&vec![&input_json()[0].clone()]).unwrap(), result);
|
||||||
|
|
||||||
|
let result = selector.select_to::<Vec<Person>>().unwrap();
|
||||||
|
assert_eq!(input_person()[0], result[0]);
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "jsonpath-wasm"
|
name = "jsonpath_wasm"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||||
description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath"
|
description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath"
|
||||||
keywords = ["library", "jsonpath", "json", "webassembly"]
|
keywords = ["library", "jsonpath", "json", "webassembly"]
|
||||||
@ -26,6 +26,9 @@ web-sys = { version = "0.3", features = ['console'] }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasm-bindgen-test = "0.2"
|
wasm-bindgen-test = "0.2"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
js-sys = "0.3"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = "s"
|
opt-level = "s"
|
||||||
|
@ -7,19 +7,19 @@ extern crate wasm_bindgen;
|
|||||||
extern crate web_sys;
|
extern crate web_sys;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use serde_json::Value;
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
use web_sys::console;
|
|
||||||
|
|
||||||
use jsonpath::filter::value_filter::JsonValueFilter;
|
use jsonpath::filter::value_filter::JsonValueFilter;
|
||||||
use jsonpath::parser::parser::{Node, NodeVisitor, Parser};
|
use jsonpath::parser::parser::{Node, NodeVisitor, Parser};
|
||||||
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
|
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
|
||||||
|
use jsonpath::Selector as _Selector;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use web_sys::console;
|
||||||
|
|
||||||
mod utils;
|
use std::result;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "wee_alloc")] {
|
if #[cfg(feature = "wee_alloc")] {
|
||||||
@ -29,11 +29,21 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "console_error_panic_hook")] {
|
||||||
|
extern crate console_error_panic_hook;
|
||||||
|
pub use self::console_error_panic_hook::set_once as set_panic_hook;
|
||||||
|
} else {
|
||||||
|
#[inline]
|
||||||
|
pub fn set_panic_hook() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
|
fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
|
||||||
let mut jf = JsonValueFilter::new_from_value(json);
|
let mut jf = JsonValueFilter::new_from_value(json);
|
||||||
jf.visit(node);
|
jf.visit(node);
|
||||||
let taken: Value = (&jf.take_value()).into();
|
let taken = &jf.take_value();
|
||||||
match JsValue::from_serde(&taken) {
|
match JsValue::from_serde(taken.deref()) {
|
||||||
Ok(js_value) => js_value,
|
Ok(js_value) => js_value,
|
||||||
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
||||||
}
|
}
|
||||||
@ -77,8 +87,8 @@ lazy_static! {
|
|||||||
static ref CACHE_JSON_IDX: Mutex<usize> = Mutex::new(0);
|
static ref CACHE_JSON_IDX: Mutex<usize> = Mutex::new(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen(js_name = allocJson)]
|
||||||
pub fn alloc_json(js_value: JsValue) -> usize {
|
pub extern fn alloc_json(js_value: JsValue) -> usize {
|
||||||
match into_serde_json(&js_value) {
|
match into_serde_json(&js_value) {
|
||||||
Ok(json) => {
|
Ok(json) => {
|
||||||
let mut map = CACHE_JSON.lock().unwrap();
|
let mut map = CACHE_JSON.lock().unwrap();
|
||||||
@ -98,8 +108,8 @@ pub fn alloc_json(js_value: JsValue) -> usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen(js_name = deallocJson)]
|
||||||
pub fn dealloc_json(ptr: usize) -> bool {
|
pub extern fn dealloc_json(ptr: usize) -> bool {
|
||||||
let mut map = CACHE_JSON.lock().unwrap();
|
let mut map = CACHE_JSON.lock().unwrap();
|
||||||
map.remove(&ptr).is_some()
|
map.remove(&ptr).is_some()
|
||||||
}
|
}
|
||||||
@ -120,14 +130,6 @@ pub fn compile(path: &str) -> JsValue {
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
/// deprecated. use selector
|
|
||||||
///
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn reader(js_value: JsValue) -> JsValue {
|
|
||||||
selector(js_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn selector(js_value: JsValue) -> JsValue {
|
pub fn selector(js_value: JsValue) -> JsValue {
|
||||||
let json = match js_value.as_f64() {
|
let json = match js_value.as_f64() {
|
||||||
@ -168,11 +170,47 @@ pub fn select(js_value: JsValue, path: &str) -> JsValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// deprecated. use select
|
/// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다.
|
||||||
///
|
///
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn read(js_value: JsValue, path: &str) -> JsValue {
|
pub struct Selector {
|
||||||
select(js_value, path)
|
selector: _Selector
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl Selector {
|
||||||
|
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Selector { selector: _Selector::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(catch)]
|
||||||
|
pub fn path(&mut self, path: &str) -> result::Result<(), JsValue> {
|
||||||
|
let _ = self.selector.path(path)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(catch)]
|
||||||
|
pub fn value(&mut self, value: JsValue) -> result::Result<(), JsValue> {
|
||||||
|
let ref_value = into_serde_json(&value)?;
|
||||||
|
let _ = self.selector.value(ref_value)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(catch, js_name = selectToStr)]
|
||||||
|
pub fn select_to_str(&mut self) -> result::Result<JsValue, JsValue> {
|
||||||
|
let json_str = self.selector.select_to_str()?;
|
||||||
|
Ok(JsValue::from_str(&json_str))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(catch, js_name = selectTo)]
|
||||||
|
pub fn select_to(&mut self) -> result::Result<JsValue, JsValue> {
|
||||||
|
let ref_value = self.selector.select_to::<RefValue>()
|
||||||
|
.map_err(|e| JsValue::from_str(&e))?;
|
||||||
|
Ok(JsValue::from_serde(&ref_value)
|
||||||
|
.map_err(|e| JsValue::from_str(&format!("{:?}", e)))?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(feature = "console_error_panic_hook")] {
|
|
||||||
extern crate console_error_panic_hook;
|
|
||||||
pub use self::console_error_panic_hook::set_once as set_panic_hook;
|
|
||||||
} else {
|
|
||||||
#[inline]
|
|
||||||
pub fn set_panic_hook() {}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +1,118 @@
|
|||||||
//! Test suite for the Web and headless browsers.
|
|
||||||
|
|
||||||
#![cfg(target_arch = "wasm32")]
|
#![cfg(target_arch = "wasm32")]
|
||||||
|
|
||||||
|
extern crate core;
|
||||||
|
extern crate js_sys;
|
||||||
|
extern crate jsonpath_wasm as jsonpath;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_json;
|
||||||
|
extern crate wasm_bindgen;
|
||||||
extern crate wasm_bindgen_test;
|
extern crate wasm_bindgen_test;
|
||||||
|
|
||||||
|
use serde_json::Value;
|
||||||
|
use wasm_bindgen::*;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
wasm_bindgen_test_configure!(run_in_browser);
|
wasm_bindgen_test_configure!(run_in_browser);
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
fn json_str() -> &'static str {
|
||||||
fn pass() {
|
r#"
|
||||||
assert_eq!(1 + 1, 2);
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_json() -> Value {
|
||||||
|
json!([{
|
||||||
|
"category" : "fiction",
|
||||||
|
"author" : "Herman Melville",
|
||||||
|
"title" : "Moby Dick",
|
||||||
|
"isbn" : "0-553-21311-3",
|
||||||
|
"price" : 8.99
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn select() {
|
||||||
|
let json: Value = jsonpath::select(JsValue::from_str(json_str()), "$..book[2]").into_serde().unwrap();
|
||||||
|
assert_eq!(json, target_json());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn compile() {
|
||||||
|
let js_value = jsonpath::compile("$..book[2]");
|
||||||
|
assert_eq!(js_value.is_function(), true);
|
||||||
|
|
||||||
|
let cb: &js_sys::Function = JsCast::unchecked_ref(js_value.as_ref());
|
||||||
|
let cb_result: JsValue = cb.call1(&js_value, &JsValue::from_str(json_str())).unwrap();
|
||||||
|
let json: Value = cb_result.into_serde().unwrap();
|
||||||
|
assert_eq!(json, target_json());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn selector() {
|
||||||
|
let js_value = jsonpath::selector(JsValue::from_str(json_str()));
|
||||||
|
assert_eq!(js_value.is_function(), true);
|
||||||
|
|
||||||
|
let cb: &js_sys::Function = JsCast::unchecked_ref(js_value.as_ref());
|
||||||
|
let cb_result: JsValue = cb.call1(&js_value, &JsValue::from_str("$..book[2]")).unwrap();
|
||||||
|
let json: Value = cb_result.into_serde().unwrap();
|
||||||
|
assert_eq!(json, target_json());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn alloc_dealloc_json() {
|
||||||
|
let ptr = jsonpath::alloc_json(JsValue::from_str(json_str()));
|
||||||
|
assert_eq!(ptr > 0, true);
|
||||||
|
|
||||||
|
let json: Value = jsonpath::select(JsValue::from_f64(ptr as f64), "$..book[2]").into_serde().unwrap();
|
||||||
|
assert_eq!(json, target_json());
|
||||||
|
|
||||||
|
assert_eq!(jsonpath::dealloc_json(ptr), true);
|
||||||
|
|
||||||
|
let err = jsonpath::select(JsValue::from_f64(ptr as f64), "$..book[2]").as_string().unwrap();
|
||||||
|
assert_eq!(err, "Invalid pointer".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn selector_struct() {
|
||||||
|
let mut selector = jsonpath::Selector::new();
|
||||||
|
selector.path("$..book[2]").unwrap();
|
||||||
|
selector.value(JsValue::from_str(json_str())).unwrap();
|
||||||
|
let json: Value = selector.select_to().unwrap().into_serde().unwrap();
|
||||||
|
assert_eq!(json, target_json());
|
||||||
}
|
}
|
170
wasm/www/css/github-corner.css
Normal file
170
wasm/www/css/github-corner.css
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/**
|
||||||
|
* GitHub Corners, page css
|
||||||
|
* Author: Tim Holman
|
||||||
|
*/
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
background: #fff;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 100;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
padding-right: 20px;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-top: 50px;
|
||||||
|
max-width: 580px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demo Code
|
||||||
|
*/
|
||||||
|
|
||||||
|
.version {
|
||||||
|
border: 2px solid #eee;
|
||||||
|
margin-top: 25px;
|
||||||
|
height: 200px;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-section {
|
||||||
|
padding: 10px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-section.dark {
|
||||||
|
background: #151513;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo {
|
||||||
|
border-right: 2px solid #eee;
|
||||||
|
position: relative;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code {
|
||||||
|
vertical-align: top;
|
||||||
|
width: 336px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code textarea {
|
||||||
|
border: 2px solid #eee;
|
||||||
|
outline: 0px;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-corner:hover .octo-arm {
|
||||||
|
animation: octocat-wave 560ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes octocat-wave {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
transform: rotate(-25deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: rotate(10deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
transform: rotate(-25deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
transform: rotate(10deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.github-corner:hover .octo-arm {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-corner .octo-arm {
|
||||||
|
animation: octocat-wave 560ms ease-in-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Footer
|
||||||
|
*/
|
||||||
|
|
||||||
|
footer {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 25px;
|
||||||
|
margin-bottom: 100px;
|
||||||
|
background: #F3F3F3;
|
||||||
|
height: 50px;
|
||||||
|
padding: 15px;
|
||||||
|
padding-left: 25px;
|
||||||
|
padding-right: 25px;
|
||||||
|
color: #2D2D2D;
|
||||||
|
font-size: 13px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: #2d2d2d;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer span {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.twitter-share-button {
|
||||||
|
margin-bottom: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Media
|
||||||
|
*/
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
height: auto;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.twitter-share-button {
|
||||||
|
margin-bottom: -8px;
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>JsonPath evaluator - Webassembly via Rust</title>
|
<title>JsonPath evaluator - Webassembly via Rust</title>
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
|
||||||
|
<link href="./css/github-corner.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body role="document">
|
<body role="document">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -15,7 +16,59 @@
|
|||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-3">
|
||||||
|
<span class="badge badge-dark" style="margin-bottom: 15px">JsonPath</span> <span>(click to try)</span>
|
||||||
|
<table class="table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#/$.store.book[*].author">$.store.book[*].author</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#$..author">$..author</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$.store.*</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$.store..price</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[2]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[-2]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[0,1]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[:2]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[1:2]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[-2:]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[2:]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[?(@.isbn)]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$.store.book[?(@.price < 10)]</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..*</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="path"><a href="#">$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
<span class="badge badge-dark" style="margin-bottom: 15px">Evaluator</span>
|
<span class="badge badge-dark" style="margin-bottom: 15px">Evaluator</span>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<textarea id="json-example" class="form-control" style="min-width: 100%" rows="20"></textarea>
|
<textarea id="json-example" class="form-control" style="min-width: 100%" rows="20"></textarea>
|
||||||
@ -29,12 +82,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-4">
|
||||||
<span class="badge badge-dark" style="margin-bottom: 15px">Result</span>
|
<span class="badge badge-dark" style="margin-bottom: 15px">Result</span>
|
||||||
<pre class="prettyprint result" id="read-result" style="background-color: transparent; border: none;"></pre>
|
<pre class="prettyprint result" id="read-result" style="background-color: transparent; border: none;"></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="https://github.com/freestrings/jsonpath" class="github-corner" aria-label="View source on GitHub">
|
||||||
|
<svg width="80" height="80" viewBox="0 0 250 250" style="position: absolute; top: 0px; right: 0px; border: 0px;" aria-hidden="true">
|
||||||
|
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" fill="#151513"></path>
|
||||||
|
<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="#ffffff" style="transform-origin: 130px 106px;"></path>
|
||||||
|
<path class="octo-body" d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="#ffffff"></path>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
<script src="./bootstrap.js"></script>
|
<script src="./bootstrap.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -16,6 +16,10 @@ function getReadResult() {
|
|||||||
return document.querySelector('#read-result');
|
return document.querySelector('#read-result');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLinks() {
|
||||||
|
return document.querySelectorAll('.path>a');
|
||||||
|
}
|
||||||
|
|
||||||
function initData(url) {
|
function initData(url) {
|
||||||
return fetch(url)
|
return fetch(url)
|
||||||
.then((res) => res.text())
|
.then((res) => res.text())
|
||||||
@ -35,8 +39,12 @@ function initEvent() {
|
|||||||
read();
|
read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLinks().forEach(function(anchor) {
|
||||||
|
anchor.href = "#" + encodeURIComponent(anchor.textContent);
|
||||||
|
});
|
||||||
|
|
||||||
function read() {
|
function read() {
|
||||||
let ret = jsonpath.read(getTextarea().value, getJsonpathInput().value);
|
let ret = jsonpath.select(getTextarea().value, getJsonpathInput().value);
|
||||||
if(typeof ret === 'string') {
|
if(typeof ret === 'string') {
|
||||||
getReadResult().innerText = ret;
|
getReadResult().innerText = ret;
|
||||||
} else {
|
} else {
|
||||||
@ -46,22 +54,26 @@ function initEvent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readPathParam() {
|
function readPathParam() {
|
||||||
let params = location.search.substr(1)
|
if(location.href.indexOf('#') > -1) {
|
||||||
.split('&')
|
readPath()
|
||||||
.map((item) => item.split('='))
|
}
|
||||||
.reduce((acc, param) => {
|
}
|
||||||
acc[param[0]] = decodeURIComponent(param[1]);
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
if(params.path) {
|
function forceClick(ctrl) {
|
||||||
getJsonpathInput().value = params.path;
|
let doc = ctrl.ownerDocument;
|
||||||
let doc = getReadBtn().ownerDocument;
|
|
||||||
let event = doc.createEvent('MouseEvents');
|
let event = doc.createEvent('MouseEvents');
|
||||||
event.initEvent('click', true, true);
|
event.initEvent('click', true, true);
|
||||||
event.synthetic = true;
|
event.synthetic = true;
|
||||||
getReadBtn().dispatchEvent(event, true);
|
ctrl.dispatchEvent(event, true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readPath() {
|
||||||
|
let query = location.href.substring(location.href.indexOf('#') + 1);
|
||||||
|
let path = decodeURIComponent(query);
|
||||||
|
getJsonpathInput().value = path;
|
||||||
|
forceClick(getReadBtn());
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onpopstate = readPath;
|
||||||
|
|
||||||
initData('data/example.json').then(initEvent).then(readPathParam);
|
initData('data/example.json').then(initEvent).then(readPathParam);
|
5
wasm/www/svg/github-corner-left.svg
Normal file
5
wasm/www/svg/github-corner-left.svg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 250 250" fill="#151513" style="position: absolute; top: 0; left: 0">
|
||||||
|
<path fill="#fff" d="M250 0L135 115h-15l-12 27L0 250V0z"/>
|
||||||
|
<path class="octo-arm" d="M122 109c15-9 9-19 9-19-3-7-2-11-2-11 1-7-3-2-3-2-4 5-2 11-2 11 3 10-5 15-9 16" style="-webkit-transform-origin: 120px 144px; transform-origin: 120px 144px"/>
|
||||||
|
<path class="octo-body" d="M135 115s-4 2-5 0l-14-14c-3-2-6-3-8-3 8-11 15-24-2-41-5-5-10-7-16-7-1-2-3-7-12-11 0 0-5 3-7 16-4 2-8 5-12 9s-7 8-9 12c-14 4-17 9-17 9 4 8 9 11 11 11 0 6 2 11 7 16 16 16 30 10 41 2 0 3 1 7 5 11l12 11c1 2-1 6-1 6z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 644 B |
5
wasm/www/svg/github-corner-right.svg
Normal file
5
wasm/www/svg/github-corner-right.svg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 250 250" fill="#151513" style="position: absolute; top: 0; right: 0">
|
||||||
|
<path d="M0 0l115 115h15l12 27 108 108V0z" fill="#fff"/>
|
||||||
|
<path class="octo-arm" d="M128 109c-15-9-9-19-9-19 3-7 2-11 2-11-1-7 3-2 3-2 4 5 2 11 2 11-3 10 5 15 9 16" style="-webkit-transform-origin: 130px 106px; transform-origin: 130px 106px"/>
|
||||||
|
<path class="octo-body" d="M115 115s4 2 5 0l14-14c3-2 6-3 8-3-8-11-15-24 2-41 5-5 10-7 16-7 1-2 3-7 12-11 0 0 5 3 7 16 4 2 8 5 12 9s7 8 9 12c14 3 17 7 17 7-4 8-9 11-11 11 0 6-2 11-7 16-16 16-30 10-41 2 0 3-1 7-5 11l-12 11c-1 1 1 5 1 5z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 641 B |
@ -61,7 +61,7 @@ let path = '$..book[?(@.price<30 && @.category=="fiction")]';
|
|||||||
let template = jpw.compile(path);
|
let template = jpw.compile(path);
|
||||||
let selector = jpw.selector(json);
|
let selector = jpw.selector(json);
|
||||||
|
|
||||||
let ptr = jpw.alloc_json(json);
|
let ptr = jpw.allocJson(json);
|
||||||
if(ptr == 0) console.error('invalid ptr');
|
if(ptr == 0) console.error('invalid ptr');
|
||||||
|
|
||||||
let iterCount = 2000;
|
let iterCount = 2000;
|
||||||
@ -83,7 +83,7 @@ run('jsonpath', iterCount, function() { jp.query(json, path) })
|
|||||||
return run('jsonpath-wasm- select-alloc', iterCount, function() { jpw.select(ptr, path) });
|
return run('jsonpath-wasm- select-alloc', iterCount, function() { jpw.select(ptr, path) });
|
||||||
})
|
})
|
||||||
.finally(function() {
|
.finally(function() {
|
||||||
if(!jpw.dealloc_json(ptr)) {
|
if(!jpw.deallocJson(ptr)) {
|
||||||
console.error('fail to dealloc');
|
console.error('fail to dealloc');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user