#json #数据转换 #转换 #反序列化JSON #转换

proteus

Proteus 旨在通过 serde 序列化,使用 JSON 反序列化,以及类似于 JavaScript JSON 语法的 JSON 转换语法,使数据的动态转换变得简单。它还支持注册自定义动作以用于语法。

6 个版本 (破坏性更新)

0.5.0 2021年10月24日
0.4.0 2020年12月30日
0.3.0 2020年12月14日
0.2.0 2020年5月25日
0.1.1 2020年1月9日

#394 in 编码

Download history 1455/week @ 2024-01-12 1902/week @ 2024-01-19 1553/week @ 2024-01-26 1465/week @ 2024-02-02 1330/week @ 2024-02-09 1372/week @ 2024-02-16 1344/week @ 2024-02-23 1235/week @ 2024-03-01 1138/week @ 2024-03-08 1142/week @ 2024-03-15 1440/week @ 2024-03-22 1438/week @ 2024-03-29 1161/week @ 2024-04-05 1370/week @ 2024-04-12 1432/week @ 2024-04-19 946/week @ 2024-04-26

5,223 monthly downloads
3 个crate中使用(直接使用2个)

MIT/Apache

105KB
2K SLoC

Proteus — 构建状态 最新版本

这个库旨在通过 serde 序列化,使用 JSON 反序列化,以及类似于 JavaScript JSON 语法的 JSON 转换语法,使数据的动态转换变得简单。它还支持注册自定义动作以用于语法。


[dependencies]
proteus = "0.1"

获取器/设置器语法

获取器和设置器语法是定制的,以支持自定义/动态动作,并且与设置器具有额外的选项几乎相同。如果需要其他解析语法,则可以使用它以与内部相同的方式构建转换。

转换语法与在 JavaScript 中访问 JSON 数据非常相似。要处理特殊字符,例如空白(空格)、方括号、引号和点,可以使用显式键语法 ["example[].blah""],它将代表以下 JSON 中的键

{
  "example[].blah" : "my value"
}

重要:操作顺序很重要。

获取器

语法 描述
这将获取顶层值,它可以是任何有效的类型:对象、数组、...
id 获取 JSON 对象的名称。例如,HashMap 中的键
[0] 获取指定索引处的 JSON 数组索引。
profile.first_name 使用点表示法组合对象名称。
profile.address[0].street 还支持使用点表示法和索引的组合。

设置器

语法 描述
这将设置目标中的顶层值
id 本身任何文本都被视为 JSON 对象的名称。
[] 此操作将源 数据 添加到数组中,如果它不存在则创建它,并且仅在 set 语法末尾有效,例如 profile.address[]
[+] 源数组应将其所有值追加到目标数组中,并且仅在 set 语法末尾有效,例如 profile.address[]
[-] 源数组值应替换目标数组中重叠索引处的值,并且仅在 set 语法末尾有效,例如 profile.address[]
{} 此操作将提供的对象合并到现有对象之上,并且仅在 set 语法末尾有效,例如 profile{}
profile.first_name 使用点表示法组合对象名称。
profile.address[0].street 还支持使用点表示法和索引的组合。

示例用法

use proteus::{actions, TransformBuilder};
use std::error::Error;

// This example show the basic usage of transformations
fn main() -> Result<(), Box<dyn Error>> {
    let input = r#"
        {
            "user_id":"111",
            "first_name":"Dean",
            "last_name":"Karn",
            "addresses": [
                { "street":"26 Here Blvd", "postal":"123456", "country":"Canada", "primary":true },
                { "street":"26 Lakeside Cottage Lane.", "postal":"654321", "country":"Canada" }
            ],
            "nested": {
                "inner":{
                    "key":"value"
                },
                "my_arr":[null,"arr_value",null]
            }
        }"#;
    let trans = TransformBuilder::default()
        .add_actions(actions!(
            ("user_id", "id"),
            (
                r#"join(" ", const("Mr."), first_name, last_name)"#,
                "full-name"
            ),
            (
                r#"join(", ", addresses[0].street, addresses[0].postal, addresses[0].country)"#,
                "address"
            ),
            ("nested.inner.key", "prev_nested"),
            ("nested.my_arr", "my_arr"),
            (r#"const("arr_value_2")"#, "my_arr[]")
        )?)
        .build()?;
    let res = trans.apply_from_str(input)?;
    println!("{}", serde_json::to_string_pretty(&res)?);
    Ok(())
}

或者当你想进行结构到结构的转换时

use proteus::{actions, TransformBuilder};
use serde::{Deserialize, Serialize};
use std::error::Error;

#[derive(Serialize)]
struct KV {
    pub key: String,
}

#[derive(Serialize)]
struct Nested {
    pub inner: KV,
    pub my_arr: Vec<Option<String>>,
}

#[derive(Serialize)]
struct Address {
    pub street: String,
    pub postal: String,
    pub country: String,
}

#[derive(Serialize)]
struct RawUserInfo {
    pub user_id: String,
    pub first_name: String,
    pub last_name: String,
    pub addresses: Vec<Address>,
    pub nested: Nested,
}

#[derive(Serialize, Deserialize)]
struct User {
    pub id: String,
    #[serde(rename = "full-name")]
    pub full_name: String,
    pub address: String,
    pub prev_nested: String,
    pub my_arr: Vec<Option<String>>,
}

// This example show the basic usage of transformations
fn main() -> Result<(), Box<dyn Error>> {
    let input = RawUserInfo {
        user_id: "111".to_string(),
        first_name: "Dean".to_string(),
        last_name: "Karn".to_string(),
        addresses: vec![
            Address {
                street: "26 Here Blvd".to_string(),
                postal: "123456".to_string(),
                country: "Canada".to_string(),
            },
            Address {
                street: "26 Lakeside Cottage Lane.".to_string(),
                postal: "654321".to_string(),
                country: "Canada".to_string(),
            },
        ],
        nested: Nested {
            inner: KV {
                key: "value".to_string(),
            },
            my_arr: vec![None, Some("arr_value".to_owned()), None],
        },
    };
    let trans = TransformBuilder::default()
        .add_actions(actions!(
            ("user_id", "id"),
            (
                r#"join(" ", const("Mr."), first_name, last_name)"#,
                "full-name"
            ),
            (
                r#"join(", ", addresses[0].street, addresses[0].postal, addresses[0].country)"#,
                "address"
            ),
            ("nested.inner.key", "prev_nested"),
            ("nested.my_arr", "my_arr"),
            (r#"const("arr_value_2")"#, "my_arr[]")
        )?)
        .build()?;
    let res: User = trans.apply_to(input)?;
    println!("{}", serde_json::to_string_pretty(&res)?);
    Ok(())
}

操作

以下都是支持的操作。

action 描述
const("Mr.") 用于定义一个常量值。
join(",", const("Mr."), first_name, last_name) 使用提供的分隔符连接一个或多个值
len(array_field) 返回字符串、数组或对象的长度(按键的数量计)。
strip_start("v", key) 从字符串值中删除提供的前缀。
strip_end("v", key) 从字符串值中删除提供的后缀。
sum(cost, taxes, const(1)) 计算一个或多个提供的值之和。
trim(key) 从字符串中去除开头和结尾的空白。
trim_start(key) 从字符串中去除开头的空白。
trim_end(key) 从字符串中去除结尾的空白。

许可证

根据您选择的许可证,在 Apache License, Version 2.0 或 MIT 许可证下授权。Apache 许可证,版本 2.0MIT 许可证
除非您明确声明,否则您提交给 Proteus 的任何贡献,根据 Apache-2.0 许可证定义,应按上述方式双重许可,而不附加任何额外条款或条件。

依赖项

~3–5MB
~93K SLoC