在使用serde_json解析过程中,是否有可能展平子对象字段?

27

#[serde(rename)] 似乎是正确的选项,但文档并没有说明它是否可行或如何实现。

这个 JSON 对象:

{
   "name" : "myobject"
   "info" : 
   {
      "counter" : "3"
      "foo" : "bar"
   }
}

相应的平的 Rust 结构体应该是:

#[derive(Deserialize)]
struct Object {
    name: String,
    #[serde(rename="info.counter")] // wrong syntax here !!
    count: i32,
    #[serde(rename="info::foo")] // neither this works
    foo: String,
}

1
需要注意的是,嵌套结构体没有性能上的劣势;你只需要担心代码组织问题。 - Shepmaster
3
目前还无法实现:https://github.com/serde-rs/serde/issues/119 - oli_obk
使用#[serde(deserialize_with = "path")]是另一个很好的选择。https://github.com/serde-rs/serde/issues/868 - Manvir
1个回答

19

没有内置的属性可以实现此功能,但您可以为自己的Object类型编写Deserialize实现,将首先反序列化到某些中间辅助表示,然后重新排列数据以获得所需的结构体。

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

use serde::{Deserialize, Deserializer};

#[derive(Debug)]
struct Object {
    name: String,
    count: i32,
    foo: String,
}

impl<'de> Deserialize<'de> for Object {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        #[derive(Deserialize)]
        struct Outer {
            name: String,
            info: Inner,
        }

        #[derive(Deserialize)]
        struct Inner {
            count: i32,
            foo: String,
        }

        let helper = Outer::deserialize(deserializer)?;
        Ok(Object {
            name: helper.name,
            count: helper.info.count,
            foo: helper.info.foo,
        })
    }
}

fn main() {
    let j = r#"{
                 "name": "myobject",
                 "info": {
                   "count": 3,
                   "foo": "bar"
                 }
               }"#;

    println!("{:#?}", serde_json::from_str::<Object>(j).unwrap());
}

输出结果为:

Object {
    name: "myobject",
    count: 3,
    foo: "bar"
}

无关紧要的嵌套出现在三个实质性不同的地方:

  1. 与其他字段相邻
  2. 在顶级自身处
  3. 在顶级以下自身处

这三种情况需要不同的处理方法。#1是在这个问题中观察到的。

要解决#2或#3,请参见如何在使用Serde反序列化对象时省略包装器/根对象?


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