在JSON对象中反序列化JSON对象(作为文本)



我正在寻找一个更好的解决方案来反序列化嵌套JSON对象,像这样

{"name":"John Doe","age":43,"address":"{"street":"10 Downing Street","city":"London"}"}

使用这段代码,我完成了工作

use serde_derive::{Deserialize, Serialize};use serde_json::{Result, Value};
#[derive(Serialize, Deserialize)]
struct Person{
name: String,
address: Value
}
#[derive(Debug, Serialize, Deserialize)]
struct Address{
street: String,
city: String
}
impl From<Person> for Address{
fn from(p: Person) -> Self {
let str_val: String = serde_json::from_value(p.address).unwrap();
let ad: Self =  serde_json::from_str(&str_val).unwrap();
ad
}
} 
fn main() -> Result<()> {
let data = r#"{"name":"John Doe","age":43,"address":"{"street":"10 Downing Street","city":"London"}"}"#;
let p: Person = serde_json::from_str(data).unwrap();
println!("{:?}", Address::from(p));
Ok(())
}

但在我看来,这可能是一个更好的方法。任何建议吗?

但在我看来,这可能是一个更好的方法。任何建议吗?

那么address: Value似乎没有用,因为在这种情况下ValueString:eprintln!("{:?}", p.address);将打印

String("{"street":"10 Downing Street","city":"London"}")

所以你可以有address: String,然后直接从它反序列化:

serde_json::from_str(&p.address).unwrap()

或者您可以使用deserialize_with或手动创建Person的反序列化器,这样您就可以递归地调用serde_json,以便在反序列化Person的同时反序列化Address

可能最大的优点是您不应该为Address分配字符串,您可以从借来的数据进行反序列化。

补充@Masklinn的回答,这里是一个基于deserialize_with的工作版本:

use serde::{Deserialize, Deserializer};
#[derive(Debug, Deserialize)]
struct Address {
street: String,
city: String,
}
#[derive(Debug, Deserialize)]
struct Person {
name: String,
#[serde(deserialize_with = "deserialize_nested_address")]
address: Address,
}
fn deserialize_nested_address<'de, D>(data: D) -> Result<Address, D::Error>
where
D: Deserializer<'de>,
{
struct AddressVisitor;
impl<'de> serde::de::Visitor<'de> for AddressVisitor {
type Value = Address;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a string containing a json encoded address")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Address, E> {
serde_json::from_str(v).map_err(E::custom)
}
}
data.deserialize_any(AddressVisitor)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = r#"{"name":"John Doe","age":43,"address":"{"street":"10 Downing Street","city":"London"}"}"#;
let p: Person = serde_json::from_str(data)?;
println!("{:#?}", p);
Ok(())
}
Person {
name: "John Doe",
address: Address {
street: "10 Downing Street",
city: "London",
},
}

当然这两种方式都可以:

use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Serialize, Deserialize)]
struct Address {
street: String,
city: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct Person {
name: String,
#[serde(
serialize_with = "serialize_nested_address",
deserialize_with = "deserialize_nested_address"
)]
address: Address,
}
fn deserialize_nested_address<'de, D>(data: D) -> Result<Address, D::Error>
where
D: Deserializer<'de>,
{
struct AddressVisitor;
impl<'de> serde::de::Visitor<'de> for AddressVisitor {
type Value = Address;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a string containing a json encoded address")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Address, E> {
serde_json::from_str(v).map_err(E::custom)
}
}
data.deserialize_any(AddressVisitor)
}
fn serialize_nested_address<S>(address: &Address, data: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::Error;
let s = serde_json::to_string(address).map_err(S::Error::custom)?;
data.serialize_str(&s)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = r#"{"name":"John Doe","age":43,"address":"{"street":"10 Downing Street","city":"London"}"}"#;
let p: Person = serde_json::from_str(data)?;
println!("{:#?}", p);
let p_ser = serde_json::to_string(&p)?;
println!("Serialized: {}", p_ser);
Ok(())
}
Person {
name: "John Doe",
address: Address {
street: "10 Downing Street",
city: "London",
},
}
Serialized: {"name":"John Doe","address":"{"street":"10 Downing Street","city":"London"}"}

最新更新