Mic*_*mer 1 parsing json rust serde
假设我们有一个 JSON 文档,其中属性之一是任意大的对象数组:
\n{\n "type": "FeatureCollection",\n "features":[\n {"type": "feature", ...},\n {"type": "feature", ...},\n ... many, many more objects ...\n ]\n}\nRun Code Online (Sandbox Code Playgroud)\n该文档甚至可能通过网络发送,因此数组内的对象数量可能事先未知。
\n该文档可能有几 GB 大。
\n如何在 Rust 中解析这样的文档(最好使用 Serde)而不先将其加载到内存中?我只对数组中的对象感兴趣。\xe2\x80\x98parent\xe2\x80\x99 对象(如果愿意)可以被忽略。
\n如果您的features数组相当接近 JSON 结构的“顶部”(即仅向下一层),则可以使用 serde 合理地做到这一点。
可悲的是,通常的#[derive(Deserialize)]机制通常不能在 JSON 结构的外部级别上使用,因为您通常需要某种状态来处理功能流,但派生的反序列化器是无状态的。所以你必须实现两个DeserializeSeed.
#[derive(Deserialize)]第一个替换外部结构上的the ,但调用next_value_seed而不是next_valueon features。这都是样板文件,我仍在等待有人将其添加到 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(())
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
下一个序列化器是您真正想要的序列化器,它将序列处理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(())
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
可爱的部分是你仍然可以对内部结构使用导出魔法。
#[derive(Deserialize, Default)]
#[serde(rename_all = "snake_case")]
enum FeatureType {
#[default]
Feature,
}
#[derive(Deserialize, Default)]
struct Feature {
#[allow(unused)]
r#type: FeatureType,
// ...
}
Run Code Online (Sandbox Code Playgroud)
使用这种混合物:
FeatureCollectionStream(|f: Feature| todo!("Do something with each feature"))
.deserialize(&mut serde_json::Deserializer::from_reader(x))?;
Run Code Online (Sandbox Code Playgroud)
带有遗漏错误处理的Playground
(参见我使用相同“技巧”的另一个答案)
| 归档时间: |
|
| 查看次数: |
212 次 |
| 最近记录: |