You'll have to write a function that recurses through the serde_json::Value
structure and replaces the keys of serde_json::Map
whenever it encounters one. That's a bit awkward to implement, as there is no 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 that rename_keys
will produce a stack overflow on deep JSON structures, but serde_json
only parses to a limited depth by default, so no need to worry. If you do need support for deeply nested structures, have a look at serde_stacker
.)
If you're not interested in the serde_json::Value
itself and just want to transform a JSON string, there's two more ways to go on about this:
- You could do the renaming on serialization, by writing a custom serializer for a wrapper struct around
serde_json::Value
. An example of such a serializer is here, but you'd have to adopt it to be recursive. (Possibly, doing it at deserialization might be easier than at serialization)
- Write a JSON tokenizer (or grab a crate that contains one) to skip creating the actual
serde_json::Value
structure and to the renaming on the token stream (no need to worry when working with GBs of JSON)