问题
I am looking an elegant way to deserialize the following input:
{
"products": [
{
"id": 1,
"ptype": "Clothes",
"description": "some data about clothes",
"metadata": {
"colors" : ["blue", "green"],
"web": false,
"size": 2
}
},
{
"id": 4,
"ptype": "Food",
"description": "text for foods",
"metadata": {
"country": "France",
"wine": true
}
},
{
"id": 12,
"ptype": "EmptyPlaceholder",
"description": "nothing at all",
"metadata": {
}
}
]
}
The json contains an array of products. A product can be identified by a ptype field. According to the type of the field the metadata object differs. For example if the ptype is Food, then the metadata for food will be a string (country) and a boolean value (wine). So the products have some fields in common, id, ptype and description and some metadata. I want to deserialize this JSON file in a Vec<Product>
.
So far I have used the following code:
use serde::{Deserialize};
use serde_json::Result;
#[derive(Deserialize, Debug)]
struct ClothesData {
colors : Vec<String>,
web : bool,
size: u32,
}
#[derive(Deserialize, Debug)]
struct FoodData {
country: String,
wine: bool,
}
#[derive(Deserialize, Debug)]
struct EmptyData {
}
#[derive(Deserialize, Debug)]
enum Metadata {
ClothesData,
FoodData,
EmptyData,
}
#[derive(Deserialize, Debug)]
enum Ptype {
Clothes,
Food,
EmptyPlaceholder
}
#[derive(Deserialize, Debug)]
struct Product {
id: u32,
ptype: Ptype,
description: Option<String>,
metadata: Metadata,
}
I am not sure how to proceed from here and I would like to ask if serde crate can do this "automatically".
回答1:
This corresponds to the "adjacently tagged" serde enum representation:
use serde::Deserialize;
use serde_json::Result;
#[derive(Deserialize, Debug)]
struct Clothes {
colors: Vec<String>,
web: bool,
size: u32,
}
#[derive(Deserialize, Debug)]
struct Food {
country: String,
wine: bool,
}
#[derive(Deserialize, Debug)]
struct Empty {}
#[derive(Deserialize, Debug)]
#[serde(tag = "ptype", content = "metadata")]
enum Kind {
Clothes(Clothes),
Food(Food),
EmptyPlaceholder(Empty),
}
#[derive(Deserialize, Debug)]
struct Product {
id: u32,
description: Option<String>,
#[serde(flatten)]
kind: Kind,
}
#[derive(Deserialize, Debug)]
struct Root {
products: Vec<Product>,
}
fn main() -> Result<()> {
let data = r#"
{
"products": [
{
"id": 1,
"ptype": "Clothes",
"description": "some data about clothes",
"metadata": {
"colors" : ["blue", "green"],
"web": false,
"size": 2
}
},
{
"id": 4,
"ptype": "Food",
"description": "text for foods",
"metadata": {
"country": "France",
"wine": true
}
},
{
"id": 12,
"ptype": "EmptyPlaceholder",
"description": "nothing at all",
"metadata": {
}
}
]
}"#;
let root: Root = serde_json::from_str(data)?;
println!("{:#?}", root);
Ok(())
}
来源:https://stackoverflow.com/questions/61645924/deserialize-variable-meta-object-with-serde