我正在嘗試使用Serde和quick-xml反序列化 XML 檔案。但是,父結構中元素的型別和項的名稱都在 XML 屬性中:
<Root>
<Attribute Name="MAKE" Type="String">Ford</Attribute>
<Attribute Name="INSURANCE_GROUP" Type="Integer">10</Attribute>
</Root>
我想將其反序列化到這個結構中:
struct Root {
make: String,
insurance_group: u8,
}
我嘗試使用父級上的 tag 屬性來指定它應該使用“Type”作為物件型別,但我不知道如何告訴它使用“Name”作為結構中的變數名。我嘗試過的所有結果都是Err value: Custom("missing field MAKE")'.
此代碼應演示該問題:
use quick_xml::de::from_str;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "Type", rename_all = "SCREAMING_SNAKE_CASE")] // What else do I add here to specify "Name"?
struct Root {
make: String,
insurance_group: u8,
}
fn main() {
println!("Hello, world!");
let xml = r#"<Root>
<Attribute Name="MAKE" Type="String">Ford</Attribute>
<Attribute Name="INSURANCE_GROUP" Type="Integer">10</Attribute>
</Root>"#;
let import: Root = from_str(xml).unwrap();
dbg!(&import);
}
理想情況下,我想直接使用(不需要 )訪問這些值,import.make但我意識到這可能不可行。matchenum
uj5u.com熱心網友回復:
我看不到一種令人信服的方法quick_xml來使用屬性作為欄位的鍵。您可以反序列化為:
use serde_with::{serde_as, DisplayFromStr};
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "Name", rename_all = "SCREAMING_SNAKE_CASE")]
enum Attribute {
Make {
#[serde(rename = "$value")]
make: String,
},
InsuranceGroup {
#[serde(rename = "$value")]
#[serde_as(as = "DisplayFromStr")]
insurance_group: u8,
},
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename = "Root")]
struct SerdeRoot {
#[serde(rename = "Attribute")]
attributes: Vec<Attribute>,
}
現在,如果您堅持使用原始資料結構,您還可以執行類似的操作
use derive_builder::Builder;
#[derive(Serialize, Clone, Deserialize, Debug, Builder)]
#[serde(try_from = "SerdeRoot", into = "SerdeRoot")]
struct Root {
make: String,
insurance_group: u8,
}
impl TryFrom<SerdeRoot> for Root {
type Error = RootBuilderError;
fn try_from(value: SerdeRoot) -> Result<Self, Self::Error> {
let mut builder = RootBuilder::default();
for a in value.attributes {
match a {
Attribute::Make { make } => builder.make(make),
Attribute::InsuranceGroup { insurance_group } => {
builder.insurance_group(insurance_group)
}
};
}
builder.build()
}
}
這最終將使您的from_str::<Root>(xml)作業如愿以償。(如果你想讓序列化作業,你還需要一個Into<SerdeRoot>實作和一些額外的欄位,但這應該很容易。)Type
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/484405.html
