Lowercasing all keys in serde_json

I'm using serde_json to parse JSON into structs. Everything's been great, except I recently came across some input files that have uppercased all their keys. Is there an easy way to accept both lowercase and uppercase keys? I thought maybe using the rename_all="UPPERCASE" container attribute might work, but it seems that would then only allow uppercase keys. I'm hoping not to have to write a custom deserializer.

Looks like no built in support so far.

This helper crate exists, but incurs a performance penalty.

Aliases exist, but that might be quite tedious.

3 Likes

Besides the helper crate shared above, another idea I had is first reading the json as a serde_json::Value type, and then mapping the object inside with all lowercase keys, like so:

use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
    phones: Vec<String>,
}

fn main() {
    let data1 = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;

    let data2 = r#"
        {
            "NAME": "John Doe",
            "aGe": 43,
            "phoNES": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;

    let p: Person = serde_json::from_str(data1).expect("Invalid JSON");
    println!("Please call {} at the number {}", p.name, p.phones[0]);

    let v: Value = serde_json::from_str(data2).expect("Invalid JSON");
    if let Value::Object(obj) = v {
        let v: Value = obj
            .into_iter()
            .map(|(k, v)| (k.to_lowercase(), v))
            .collect();
        let p: Person = serde_json::from_value(v).unwrap();
        println!("Please call {} at the number {}", p.name, p.phones[0]);
    }
}

But at that point you might just want to write a deserializer :wink:

Thanks. It looks like case insensitive deserialization is something that a lot of people want but has been stuck for years now.

I think I'm just going to sprinkle alias everywhere. Thanks for the info.

Looking at the code for serde_aux, it looks like that's exactly what it's doing.