反序列化 JSON 包含不同类型对象的数组
Deserializing JSON array containing different types of object
所以我有一个看起来像这样的 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 结构,因此我对任何需要这样做的解决方案都不感兴趣。
我认为您可以使用通用数据类型。您可以在 book
上找到更多相关信息
按如下方式使用自定义解串器
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);
}
感谢 的回答,我设法找到了一个非常适合我需要的解决方案。
基本上我重新安排了 Deserializer 以遍历整个属性数组并尝试将其中的每个对象与 Enum 变体匹配。我喜欢这个,因为我可以很容易地映射一个新的属性,如果涉及到它并且感觉更灵活type-wise。
无论如何,这是它的代码:
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);
}
所以我有一个看起来像这样的 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 结构,因此我对任何需要这样做的解决方案都不感兴趣。
我认为您可以使用通用数据类型。您可以在 book
上找到更多相关信息按如下方式使用自定义解串器
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);
}
感谢
基本上我重新安排了 Deserializer 以遍历整个属性数组并尝试将其中的每个对象与 Enum 变体匹配。我喜欢这个,因为我可以很容易地映射一个新的属性,如果涉及到它并且感觉更灵活type-wise。
无论如何,这是它的代码:
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);
}