使用Serde反序列化对象时,是否可以忽略包装器/根对象?

时间:2019-02-12 20:03:03

标签: rust serde

我有以下对象:

{
  "data": {
    "id": 1,
    "name": "South America",
    "countries": {
      "data": [
        {
          "id": 122,
          "name": "Brazil",
          "capital": "Brasilia"
        }
      ]
    }
  }
}

我想定义两个结构,ContinentCountry,省略不增加价值的data包装。

1 个答案:

答案 0 :(得分:3)

我将使用可直接用于删除顶级嵌套的wrapper结构以及通过消除反序列化数据结构中嵌套级别的#[serde(with = "...")]属性来实现此功能。


use serde::{Deserialize, Deserializer};

#[derive(Deserialize, Debug)]
struct Continent {
    id: u64,
    name: String,
    #[serde(with = "Wrapper")]
    countries: Vec<Country>,
}

#[derive(Deserialize, Debug)]
struct Country {
    id: u64,
    name: String,
    capital: String,
}

#[derive(Deserialize)]
struct Wrapper<T> {
    data: T,
}

impl<T> Wrapper<T> {
    fn deserialize<'de, D>(deserializer: D) -> Result<T, D::Error>
    where
        T: Deserialize<'de>,
        D: Deserializer<'de>,
    {
        let wrapper = <Self as Deserialize>::deserialize(deserializer)?;
        Ok(wrapper.data)
    }
}

fn main() -> serde_json::Result<()> {
    let j = r#"
        {
          "data": {
            "id": 1,
            "name": "South America",
            "countries": {
              "data": [
                {
                  "id": 122,
                  "name": "Brazil",
                  "capital": "Brasilia"
                }
              ]
            }
          }
        }"#;

    let wrapper: Wrapper<Continent> = serde_json::from_str(j)?;
    println!("{:#?}", wrapper.data);

    Ok(())
}

在三个明显不同的地方会出现无关紧要的嵌套:

  1. 与其他字段相邻
  2. 本身是最高级别
  3. 本身位于顶层以下

这三种方法都需要不同的方法。在这个问题中观察到#2和#3。

要解决#1,请参见Is it possible to flatten sub-object fields while parsing with serde_json?