#jsonpath #json #webassembly #nodejs #javascript

jsonpath_lib

It is JsonPath engine written in Rust. it provide a similar API interface in Webassembly and Javascript also. - Webassembly Demo: https://freestrings.github.io/jsonpath

12 releases

new 0.1.11 Apr 15, 2019
0.1.10 Apr 13, 2019
0.1.7 Mar 26, 2019

#29 in Parser tooling

Download history 23/week @ 2019-03-04 31/week @ 2019-03-11 40/week @ 2019-03-18 120/week @ 2019-03-25 38/week @ 2019-04-01 101/week @ 2019-04-08

120 downloads per month

MIT license

421KB
4.5K SLoC

Rust 4K SLoC // 0.1% comments JavaScript 603 SLoC Shell 96 SLoC // 0.0% comments

jsonpath_lib

Build Status crates.io Crates.io npm npm npm

Rust 버전 JsonPath 구현이다. WebassemblyJavascript에서도 유사한 API 인터페이스를 제공 한다.

It is JsonPath JsonPath engine written in Rust. it provide a similar API interface in Webassembly and Javascript also.

Rust API

Javascript API


Rust API

jsonpath_lib crate

Go to creates.io

extern crate jsonpath_lib as jsonpath;
#[macro_use]
extern crate serde_json;

Rust - jsonpath::Selector struct

#[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).into() /*Parameter type will be changed from `RefValue` to `&Value` since `0.1.12`*/ ).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)

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)

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)

#[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)

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)

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)

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
// browser
import * as jsonpath from "jsonpath-wasm";
// NodeJs
const jsonpath = require('jsonpath-wasm');
jsonpath-rs (NodeJS only)

Goto npmjs.org

const jsonpath = require('jsonpath-rs');

javascript - Selector class

jsonpath-wasm

wasm-bindgen 리턴 타입 제약 때문에 빌더 패턴은 지원하지 않는다.

It does not support builder-pattern due to the return type restriction of wasm-bindgen.

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
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)

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]');

console.log(
    JSON.stringify(ret) == JSON.stringify(selectAsString),
    JSON.stringify(ret) == JSON.stringify(selectAsObj)
);

// => true, true

Javascript - jsonpath.compile(jsonpath: string)

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);

console.log(
    JSON.stringify(ret) == JSON.stringify(selectAsString),
    JSON.stringify(ret) == JSON.stringify(selectAsObj)
);

// => true, true

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);

console.log(
        JSON.stringify(ret2) == JSON.stringify(selectAsString2),
        JSON.stringify(ret2) == JSON.stringify(selectAsObj2)
);

// => true, true

Javascript - jsonpath.selector(json: string|object)

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);
// or as json string 
// let selector = jsonpath.selector(JSON.stringify(jsonObj));

let select1 = selector('$..friends[0]');
let select2 = selector('$..friends[1]');

console.log(
    JSON.stringify(ret1) == JSON.stringify(select1),
    JSON.stringify(ret2) == JSON.stringify(select2)
);

// => true, true

Javascript - allocJson, deallocJson (Webassembly Only)

wasm-bindgen은 Javascript와 Webassembly간 값을 주고받을 때 JSON 객체는 String으로 변환되기 때문에, 반복해서 사용되는 JSON 객체는 Webassembly 영역에 생성해 두면 성능에 도움이 된다.

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.

const jsonpath = require('jsonpath-wasm');

let jsonObj = {
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
    ]
};

// allocate jsonObj in webassembly
let ptr = jsonpath.allocJson(jsonObj);

// `0` is invalid pointer
if(ptr == 0) {
    console.error('invalid ptr'); 
}

let path = '$..friends[0]';
let template = jsonpath.compile(path);
let selector = jsonpath.selector(jsonObj);
// create selector as pointer
let ptrSelector = jsonpath.selector(ptr);

let ret1 = selector(path)
let ret2 = ptrSelector(path)
let ret3 = template(jsonObj);
// select as pointer
let ret4 = template(ptr);
let ret5 = jsonpath.select(jsonObj, path);
// select as pointer
let ret6 = jsonpath.select(ptr, path);

console.log(
    JSON.stringify(ret1) == JSON.stringify(ret2),
    JSON.stringify(ret1) == JSON.stringify(ret3),
    JSON.stringify(ret1) == JSON.stringify(ret4),
    JSON.stringify(ret1) == JSON.stringify(ret5),
    JSON.stringify(ret1) == JSON.stringify(ret6));

// => true true true true true

jsonpath.deallocJson(ptr);

Dependencies

~4.5MB
~77K SLoC