rust 将serde_json值键转换为camelCase

2vuwiymt  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(350)

我正在编写一个CLI工具,它读取JSON文件,并将JSON对象键转换为camelCase。
因为这应该适用于任何JSON文件,所以我显然不能只使用强类型,然后再使用#[serde(rename_all = "camelCase")]
serde_json中,我似乎找不到一种明显的方法来使它使用serde显然已经存在的重命名代码,并将其应用于serde_json::value::Value
我是不是漏掉了什么明显的东西?

v09wglhw

v09wglhw1#

你必须写一个函数,递归通过serde_json::Value结构,并在遇到serde_json::Map时替换它的键。这有点难以实现,因为没有Map::drain

fn rename_keys(json: &mut serde_json::Value) {
    match json {
        serde_json::Value::Array(a) => a.iter_mut().for_each(rename_keys),
        serde_json::Value::Object(o) => {
            let mut replace = serde_json::Map::with_capacity(o.len());
            o.retain(|k, v| {
                rename_keys(v);
                replace.insert(
                    heck::ToLowerCamelCase::to_lower_camel_case(k.as_str()),
                    std::mem::replace(v, serde_json::Value::Null),
                );
                true
            });
            *o = replace;
        }
        _ => (),
    }
}

use std::io::Read;
fn main() {
    let mut stdin = vec![];
    std::io::stdin()
        .read_to_end(&mut stdin)
        .expect("Read stdin");
    let mut json = serde_json::from_slice::<serde_json::Value>(&stdin).expect("Parse Json");
    rename_keys(&mut json);
    println!("{}", serde_json::to_string_pretty(&json).unwrap());
}

(Note rename_keys将在深度JSON结构上产生堆栈溢出,但是serde_json默认情况下只解析到有限的深度,所以不必担心。如果确实需要对深度嵌套结构的支持,请查看serde_stacker。)
如果您对serde_json::Value本身不感兴趣,只想转换JSON字符串,还有两种方法可以继续:

  • 您可以在序列化时进行重命名,方法是为围绕serde_json::Value的 Package 结构编写一个自定义序列化程序。这里有一个这样的序列化程序的示例,但您必须采用它来实现递归。(可能在反序列化时进行重命名比在序列化时更容易)
  • 编写一个JSON tokenizer(或获取一个包含它的crate),跳过创建实际的serde_json::Value结构和对令牌流的重命名(使用JSON的GB时无需担心)

相关问题