假设我们有一个JSON文档,其中一个属性是任意大的对象数组:

{
    "type": "FeatureCollection",
    "features":[
      {"type": "feature", ...},
      {"type": "feature", ...},
      ... many, many more objects ...
    ]
}

文档甚至可能通过网络发送,因此数组中的对象数量可能事先是未知的.

文档可能有几个千兆字节大.

我如何才能在Rust(最好是使用Serde)中解析这样的文档,而不是首先将其加载到内存中?我只对数组中的对象感兴趣.可以忽略"父"对象(如果您愿意).

推荐答案

如果您的features数组相当接近您的JSON struct 的"顶部"(即只向下一层),那么您可以合理地使用serde来做到这一点.

可悲的是,通常的#[derive(Deserialize)]机制通常不能在JSON struct 的外层使用,因为您通常需要某种状态来处理特性流,但派生的反序列化程序是无状态的.所以你必须实现两个DeserializeSeed.

第一个替换了外层 struct 上的#[derive(Deserialize)],但在features上调用next_value_seed而不是next_value.这些都是样板文件,我还在等待有人将其添加到serde的派生宏中:

struct FeatureCollectionStream<F>(F);
impl<'de, F: FnMut(Feature)> DeserializeSeed<'de> for FeatureCollectionStream<F> {
    type Value = ();

    fn deserialize<D>(self, d: D) -> Result<Self::Value, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        return d.deserialize_struct("FeatureCollection", &["type", "features"], FCV(self.0));
        struct FCV<F>(F);
        impl<'de, F: FnMut(Feature)> Visitor<'de> for FCV<F> {
            type Value = ();

            fn visit_map<A: MapAccess<'de>>(mut self, mut map: A) -> Result<Self::Value, A::Error> {
                while let Some(k) = map.next_key::<String>()? {
                    match k.as_str() {
                        "type" => {
                            map.next_value::<String>()?;
                        }
                        "features" => map.next_value_seed(FeatureStream(&mut self.0))?,
                        s => return Err(todo!()),
                    }
                }
                Ok(())
            }
        }
    }
}

下一个序列化程序是您实际需要的,它将Feature的序列作为流处理:

struct FeatureStream<F>(F);
impl<'de, F: FnMut(Feature)> DeserializeSeed<'de> for FeatureStream<F> {
    type Value = ();

    fn deserialize<D>(self, d: D) -> Result<Self::Value, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        return d.deserialize_seq(FV(self.0));
        struct FV<F>(F);
        impl<'de, F: FnMut(Feature)> Visitor<'de> for FV<F> {
            type Value = ();

            fn visit_seq<A: serde::de::SeqAccess<'de>>(
                mut self,
                mut seq: A,
            ) -> Result<Self::Value, A::Error> {
                while let Some(f) = seq.next_element()? {
                    (self.0)(f)
                }
                Ok(())
            }
        }
    }
}

可爱的是,你仍然可以对内部 struct 使用派生魔法.

#[derive(Deserialize, Default)]
#[serde(rename_all = "snake_case")]
enum FeatureType {
    #[default]
    Feature,
}

#[derive(Deserialize, Default)]
struct Feature {
    #[allow(unused)]
    r#type: FeatureType,
    // ...   
}

使用这个混合物:

FeatureCollectionStream(|f: Feature| todo!("Do something with each feature"))
    .deserialize(&mut serde_json::Deserializer::from_reader(x))?;

带有遗漏错误处理的Playground

(C.F.另有answer by me人采用同样的"伎俩")

Json相关问答推荐

使用JSONata将具有相同键的字典合并

如何在Gatsby/Reaction中获取JSON-File子 node

如何使用JQ打印每个根级对象键一行?

如何创建可由Gin序列化到json的排序键值映射?

写入JSON文件的流

Terraform迭代JSON文件以获取键值对

Jolt-Json转换:通过引用标识符(而不是索引)设置值

Ansible - 将文件内容添加到字典中

JOLT分裂和数组数据

jq - 将父键值提取为子元素旁边的逗号分隔值

为什么解析的字典相等而腌制的字典不相等?

用于遮蔽卡的 Jolt 规格

使用 JQ 从文件中删除重复的 JSON 块

N1QL 搜索对象内的某些对象

无法向 Json 数组添加新元素

如何使用 Swiftui 判断 JSON 是否缺少键值对

一起使用 Argparse 和 Json

哪个更好:Json 或 XML (PHP)

杰克逊在通用列表中读取 json

如何使用 Jackson 的 objectMapper 反序列化接口字段?