反序列化包含不同类型对象的JSON数组

5

我有一个JSON,看起来像这样:

{
  "name": "customer",
  "properties": [
    {
      "name": "id",
      "type": "int",
      "value": 32
    },
    {
      "name": "name",
      "type": "string",
      "value": "John"
    }
  ]
}

目前我正在将数据反序列化为以下结构集:

#[derive(Serialize, Deserialize, Debug)]
struct Customer {
    name: String,
    properties: Vec<Property>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "name", content = "value")]
enum Property {
    #[serde(rename = "id")]
    Id(i32),
    #[serde(rename = "name")]
    Name(String),
}

为了避免每次访问属性时都要匹配枚举,我希望将其反序列化为一个类似于以下结构的结构体:

struct Customer {
  name: String,
  properties: Properties,
}

struct Properties {
  id: i32, // will be 32 as in the object containing the name "id".
  name: String, // will be John as in the object containing the name "name".
}

这是 serde 库是否以某种方式允许的内容?如果是,您能否提供一个示例来实现这一点?

请注意,我不能干扰实际的json结构,因此我不对需要进行任何更改的解决方案感兴趣。

3个回答

3
通过使用以下自定义反序列化程序
extern crate serde_json; // 1.0.32
extern crate serde; // 1.0.80
#[macro_use] extern crate serde_derive;

use serde::de::{Deserializer, SeqAccess, Visitor};
use std::fmt;


#[derive(Serialize, Deserialize)]
struct Customer {
    name: String,
    #[serde(deserialize_with = "parse_property")]
    properties: Property,
}

// #[derive(Default, Debug, Deserialize)]
#[derive(Default, Serialize, Deserialize, Debug)]
struct Property {
    id: i32,
    name: String,
}

#[derive(Default, Serialize, Deserialize, Debug)]
struct Key {
    name: String,
    value: i32,
}

#[derive(Default, Serialize, Deserialize, Debug)]
struct Val {
    name: String,
    value: String
}

fn parse_property<'de, D>(deserializer: D) -> Result<Property, D::Error>
where
    D: Deserializer<'de>,
{
    struct PropertyParser;
    impl<'de> Visitor<'de> for PropertyParser
    {
        type Value = Property;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("expect [key, val]")
        }
        
        fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
            println!("In custom deserializer");
            let mut prop = Property { ..Default::default() };
            
            let tmp = seq.next_element::<Key>()?;
            if let Some(a) = tmp {
                prop.id = a.value;
            };
            
            let tmp = seq.next_element::<Val>()?;
            if let Some(b) = tmp {
                prop.name = b.value;
            };
            
            Ok(prop)
        }
    }

    deserializer.deserialize_any(PropertyParser{})
}


fn main() {
    println!("Hello, world!");
    let data = r#"
        {
  "name": "customer",
  "properties": [
    {
      "name": "id",
      "type": "int",
      "value": 32
    },
    {
      "name": "name",
      "type": "string",
      "value": "John"
    }
  ]
}"#;

    let p: Customer = serde_json::from_str(data).unwrap();

    println!("Please call {} at the number {} {}", p.name, p.properties.id, p.properties.name);

}

playground


1

感谢 edkeveked's 的答案,我成功找到了一个很好地解决方案。

基本上,我重新排列了反序列化器,循环遍历整个属性数组,并尝试将其中的每个对象与枚举变量匹配。我喜欢这种方式,因为如果未来需要映射新属性,我可以轻松地完成,并且它在类型方面更加灵活。

无论如何,以下是代码:

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

use serde::de::{Deserializer, SeqAccess, Visitor};
use std::fmt;

#[derive(Serialize, Deserialize, Debug)]
struct Customer {
    name: String,
    #[serde(deserialize_with = "parse_property")]
    properties: CustomerProps,
}

#[derive(Default, Serialize, Deserialize, Debug)]
struct CustomerProps {
    id: i32,
    name: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "name", content = "value")]
enum Property {
    #[serde(rename = "id")]
    Id(i32),
    #[serde(rename = "name")]
    Name(String),
}

fn parse_property<'de, D>(deserializer: D) -> Result<CustomerProps, D::Error>
where
    D: Deserializer<'de>,
{
    struct PropertyParser;
    impl<'de> Visitor<'de> for PropertyParser {
        type Value = CustomerProps;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("[u64, f32, usize]")
        }

        fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
            let mut prop = CustomerProps {
                ..Default::default()
            };
            while let Some(tmp) = seq.next_element::<Property>()? {
                match tmp {
                    Property::Id(id) => prop.id = id,
                    Property::Name(name) => prop.name = name,
                }
            }
            Ok(prop)
        }
    }
    deserializer.deserialize_any(PropertyParser {})
}

fn main() {
    let data = r#"{
        "name": "customer",
        "properties": [
            {
                "name": "id",
                "type": "int",
                "value": 32
            },
            {
                "name": "name",
                "type": "string",
                "value": "John"
            }
        ]
    }"#;

    let p: Customer = serde_json::from_str(data).unwrap();

    println!("Please call {} at the number {} {}", p.name, p.properties.id, p.properties.name);
}

-2

我认为您可以使用通用数据类型。您可以在书籍中找到更多信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接