11

JSON を返す Web サービスにフックするプログラムについて書いています。

特定のプロパティがそこにない場合、値を除外する代わりに、すべてのフィールドを空の文字列として空のオブジェクトを提供します。プロパティが存在する場合、一部のプロパティはu64. Serdeがこのケースを処理できるようにするにはどうすればよいですか?

さび構造

#[derive(Clone, Debug, Deserialize)]
struct WebResponse {
    foo: Vec<Foo>,
}

#[derive(Clone, Debug, Deserialize)]
struct Foo {
    points: Points,
}

#[derive(Clone, Debug, Deserialize)]
struct Points {
    x: u64,
    y: u64,
    name: String,
}

JSON の例

{
    "foo":[
        {
            "points":{
                "x":"",
                "y":"",
                "name":""
            }
        },
        {
            "points":{
                "x":78,
                "y":92,
                "name":"bar"
            }
        }
    ]
}
4

2 に答える 2

14

Serde は、ほとんどの部分で派生実装を使用しながら、型のシリアライゼーションまたはデシリアライゼーションをカスタマイズするために使用できる興味深い属性の選択をサポートしています。

あなたの場合、複数のタイプのいずれかとして指定できるフィールドをデコードできる必要があり、問題のあるフィールドをデコードする方法を決定するために他のフィールドからの情報は必要ありません。注釈は、問題を解決するの#[serde(deserialize_with="$path")]に適しています。

空の文字列または整数値を にデコードする関数を定義する必要がありますu64。同じ動作が必要なので、両方のフィールドに同じ関数を使用できます。この関数はカスタムVisitorを使用して、文字列と整数の両方を処理できるようにします。少し長いですが、Serde があなたのために行っているすべての作業に感謝します!

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use serde::Deserializer;
use serde::de::{self, Unexpected};
use std::fmt;

#[derive(Clone, Debug, Deserialize)]
struct WebResponse {
    foo: Vec<Foo>,
}

#[derive(Clone, Debug, Deserialize)]
struct Foo {
    points: Points,
}

#[derive(Clone, Debug, Deserialize)]
struct Points {
    #[serde(deserialize_with = "deserialize_u64_or_empty_string")]
    x: u64,
    #[serde(deserialize_with = "deserialize_u64_or_empty_string")]
    y: u64,
    name: String,
}

struct DeserializeU64OrEmptyStringVisitor;

impl<'de> de::Visitor<'de> for DeserializeU64OrEmptyStringVisitor {
    type Value = u64;

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

    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
    where
        E: de::Error,
    {
        Ok(v)
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: de::Error,
    {
        if v == "" {
            Ok(0)
        } else {
            Err(E::invalid_value(Unexpected::Str(v), &self))
        }
    }
}

fn deserialize_u64_or_empty_string<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
    D: Deserializer<'de>,
{
    deserializer.deserialize_any(DeserializeU64OrEmptyStringVisitor)
}

fn main() {
    let value = serde_json::from_str::<WebResponse>(
        r#"{
        "foo": [
            {
                "points": {
                    "x": "",
                    "y": "",
                    "name": ""
                }
            },
            {
                "points": {
                    "x": 78,
                    "y": 92,
                    "name": "bar"
                }
            }
        ]
    }"#,
    );
    println!("{:?}", value);
}

Cargo.toml:

[dependencies]
serde = "1.0.15"
serde_json = "1.0.4"
serde_derive = "1.0.15"
于 2016-06-17T00:33:52.363 に答える