#json-path #json-query #json #查询引擎 #查询 #wasm #lua

jsonpath_lib

这是用 Rust 编写的 JsonPath 引擎。它还提供了 Webassembly 和 Javascript 中的类似 API 接口。 - Webassembly 示例:https://freestrings.github.io/jsonpath

21 个版本

使用旧的 Rust 2015

0.3.0 2021 年 6 月 3 日
0.2.6 2020 年 12 月 16 日
0.2.5 2020 年 4 月 15 日
0.2.4 2020 年 2 月 14 日
0.1.7 2019 年 3 月 26 日

#125解析器实现

Download history 49951/week @ 2024-03-14 45079/week @ 2024-03-21 61383/week @ 2024-03-28 45786/week @ 2024-04-04 66181/week @ 2024-04-11 67235/week @ 2024-04-18 58172/week @ 2024-04-25 58651/week @ 2024-05-02 58217/week @ 2024-05-09 70686/week @ 2024-05-16 69817/week @ 2024-05-23 57648/week @ 2024-05-30 50142/week @ 2024-06-06 56037/week @ 2024-06-13 57730/week @ 2024-06-20 40470/week @ 2024-06-27

214,412 每月下载量
92 包 (23 个直接) 中使用

MIT 许可证

285KB
3.5K SLoC

jsonpath_lib

Build Status crates.io npm Codecov

Rust 版本的 JsonPath 实现,在 WebassemblyJavascript 中也提供了相似的 API 接口。

这是用 Rust 编写的 JsonPath 引擎。它还在 WebassemblyJavascript 中提供了相似的 API 接口。

Rust API

jsonpath_lib 包

前往 jsonpath_lib creates.io

extern crate jsonpath_lib as jsonpath;
Rust - jsonpath::Selector 结构体
#[derive(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(&json_obj)
    .select().unwrap();

assert_eq!(vec![&json!({"name": "친구3", "age": 30})], result);

let result = selector.select_as_str().unwrap();
assert_eq!(r#"[{"name":"친구3","age":30}]"#, result);

let result = selector.select_as::<Friend>().unwrap();
assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result);
Rust - jsonpath::SelectorMut 结构体
let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let mut selector_mut = SelectorMut::new();

let result = selector_mut
    .str_path("$..[?(@.age == 20)].age").unwrap()
    .value(json_obj)
    .replace_with(&mut |v| {
        let age = if let Value::Number(n) = v {
            n.as_u64().unwrap() * 2
        } else {
            0
        };

        Some(json!(age))
    }).unwrap()
    .take().unwrap();

assert_eq!(result, json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 40},
            {"name": "친구2", "age": 40}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]}));
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();

assert_eq!(json, vec![
    &json!({"name": "친구3", "age": 30}),
    &json!({"name": "친구1", "age": 20})
]);
Rust - jsonpath::select_as_str(json_str: &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:🇩🇪:DeserializeOwned`>(json_str: &str, jsonpath: &str)
#[derive(Deserialize, PartialEq, Debug)]
struct Person {
    name: String,
    age: u8,
    phones: Vec<String>,
}

let ret: Vec<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!(ret[0], person);
Rust - jsonpath::Compiled::compile(jsonpath: &str)
let template = jsonpath::Compiled::compile("$..friends[0]").unwrap();

let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let json = template.select(&json_obj).unwrap();

assert_eq!(json, vec![
    &json!({"name": "친구3", "age": 30}),
    &json!({"name": "친구1", "age": 20})
]);
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();

assert_eq!(json, vec![
    &json!({"name": "친구3", "age": 30}),
    &json!({"name": "친구1", "age": 20})
]);

let json = selector("$..friends[1]").unwrap();

assert_eq!(json, vec![
    &json!({"name": "친구4"}),
    &json!({"name": "친구2", "age": 20})
]);
Rust - jsonpath::selector_as<T: serde:🇩🇪: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(Deserialize, PartialEq, Debug)]
struct Friend {
    name: String,
    age: Option<u8>,
}

let mut selector = jsonpath::selector_as::<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);
Rust - jsonpath::delete(value: &Value, path: &str)
let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let ret = jsonpath::delete(json_obj, "$..[?(20 == @.age)]").unwrap();

assert_eq!(ret, json!({
    "school": {
        "friends": [
            null,
            null
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]}));
Rust - jsonpath::replace_with<F: FnMut(&Value) -> Value>(value: &Value, path: &str, fun: &mut F)
let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let ret = jsonpath::replace_with(json_obj, "$..[?(@.age == 20)].age", &mut |v| {
    let age = if let Value::Number(n) = v {
        n.as_u64().unwrap() * 2
    } else {
        0
    };

    Some(json!(age))
}).unwrap();

assert_eq!(ret, json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 40},
            {"name": "친구2", "age": 40}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]}));

Rust - 其他示例

JavaScript API

npm 包
jsonpath-wasm

前往 jsonpath-wasm npmjs.org

// browser
import * as jsonpath from "jsonpath-wasm";
// NodeJs
const jsonpath = require('jsonpath-wasm');
jsonpath-wasm

由于 wasm-bindgen 的返回类型限制,不支持 builder-pattern

由于 wasm-bindgen 的返回类型限制,不支持 builder-pattern

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 retObj = selector.select();

console.log(JSON.stringify(ret) == JSON.stringify(retObj));

// => true

构建器模式限制与 Selector 类 相同。

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

let selector = new jsonpath.SelectorMut();
selector.path('$..[?(@.age == 20)]');

{
    selector.value(jsonObj);
    selector.deleteValue();

    let resultObj = {
        'school': {'friends': [null, null]},
        'friends': [
            {'name': '친구3', 'age': 30},
            {'name': '친구4'},
        ],
    };
    console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj));
    
    // => true
}

{
    selector.value(jsonObj);
    selector.replaceWith((v) => {
        v.age = v.age * 2;
        return v;
    });

    let resultObj = {
        'school': {
            'friends': [
                {'name': '친구1', 'age': 40},
                {'name': '친구2', 'age': 40},
            ],
        },
        'friends': [
            {'name': '친구3', 'age': 30},
            {'name': '친구4'},
        ],
    };
    console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj));
    
    // => 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 error = jsonpath.compile('');
console.log(typeof error, error); //string 'path error'

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 - jsonpath.deleteValue(json: 字符串|对象, path: 字符串)
let jsonObj = {
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
    ]
};

let _1 = jsonpath.deleteValue(jsonObj, '$..friends[0]');
let result = jsonpath.deleteValue(_1, '$..friends[1]');

console.log(JSON.stringify(result) !== JSON.stringify({
    "school": { "friends": [null, null]},
    "friends": [null, null]
}));

// => true

JavaScript - jsonpath.replaceWith(json: 字符串|对象, path: 字符串, fun: 函数(json: 对象) => json: 对象)
let jsonObj = {
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
    ]
};

let result = jsonpath.replaceWith(jsonObj, '$..friends[0]', (v) => {
    v.age = v.age * 2;
    return v;
});

console.log(JSON.stringify(result) === JSON.stringify({
    "school": {
        "friends": [
            {"name": "친구1", "age": 40},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 60},
        {"name": "친구4"}
    ]
}));

// => true

JavaScript - 其他示例

依赖关系

~1.4–2.4MB
~47K SLoC