Как я могу использовать Serde для десериализации искаженного JSON с True / False? - PullRequest
4 голосов
/ 04 февраля 2020

Как я могу десериализовать следующее искаженное JSON, используя Rust's serde :

{
  "value": True
}

Используя этот ответ , я попробовал следующее решение:

#[macro_use]
extern crate serde_derive; // 1.0.66
extern crate serde; // 1.0.66
extern crate serde_json; // 1.0.21


use serde::de;
use std::fmt;

#[derive(Debug, PartialEq, Deserialize)]
pub struct Foo {
    #[serde(deserialize_with = "deserialize_capitalized_bool")]
    pub bar: bool,
}

fn deserialize_capitalized_bool<'de, D>(
    deserializer: D,
) -> Result<bool, D::Error>
where
    D: de::Deserializer<'de>,
{
    struct CapitalizedBoolVisitor;

    impl<'de> de::Visitor<'de> for CapitalizedBoolVisitor {
        type Value = bool;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a True or False string")
        }

        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
        where
            E: de::Error,
        {
            if v == &['T' as u8, 'r' as u8, 'e' as u8] {
                Ok(true)
            } else if v
                == &['F' as u8, 'a' as u8, 'l' as u8, 's' as u8, 'e' as u8]
            {
                Ok(false)
            } else {
                unimplemented!();
            }
        }
    }

    deserializer.deserialize_any(CapitalizedBoolVisitor)
}

fn main() {
    let json = r#"{
        "bar": True
    }"#;

    let foo: Foo = serde_json::from_str(json).unwrap();

    let expected = Foo {
        bar: true
    };
    assert_eq!(foo, expected);
}

работающий на игровой площадке

Проблема, насколько я могу судить, состоит в том, что ввод не распознается как какой-либо правильный тип, поэтому ни один из API посетителей работают здесь.

ОБНОВЛЕНИЕ (2020-02-05) :

Очевидно, что это невозможно решить с помощью serde_json (один можно было бы использовать пользовательский формат данных или форк serde_json, чтобы добавить эту функцию, так как serde_json не имеет дело с неверным вводом, см. ответ сопровождающего ).

A Хакерское решение для тех, у кого есть подобные проблемы, состоит в замене экземпляров True и False в необработанной строке ответа на true и false. Это определенно не идеально, поскольку, если строка содержит True или False, они также будут заменены, но, возможно, это приемлемое решение для определенных c вариантов использования.

Ответы [ 2 ]

2 голосов
/ 05 февраля 2020

Как правило, вы можете десериализовать ввод с определенной библиотекой, только если вход находится в формате данных, для которого предназначена библиотека.

Так, например, если вы не используете JSON, CBOR, MessagePack тогда вы не можете использовать serde_ json, serde_cbor или serde_messagepack, чтобы десериализовать его.

Отображаемый вами ввод выглядит как YAML, поэтому вы можете попробовать serde_yaml.

fn main() {
    let input = r#" {
                      "value": True
                    } "#;
    println!("{:#?}", serde_yaml::from_str::<serde_yaml::Value>(input).unwrap());
}

В других Другими словами, тот факт, что данные недействительны JSON, говорит о том, какую библиотеку не использовать - serde_ json. Чтобы найти правильную библиотеку, более полезно найти формат, в котором данные имеют значение , допустимое в.

2 голосов
/ 04 февраля 2020

Это недопустимо JSON, поэтому вы не можете использовать serde_json для его десериализации.

Булевыми константами в JSON являются true и false в нижнем регистре.

...