使用名称和类型作为属性反序列化 XML
Deserialising XML with name and type as attributes
我正在尝试使用 Serde and 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,
}
我试过使用父级的标签属性来指定它应该使用“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
访问这些值(不需要 match
和 enum
),但我意识到这可能不可行。
我看不出有什么方法可以说服 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
的一些额外字段,但这应该很容易。)
我正在尝试使用 Serde and 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,
}
我试过使用父级的标签属性来指定它应该使用“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
访问这些值(不需要 match
和 enum
),但我意识到这可能不可行。
我看不出有什么方法可以说服 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
的一些额外字段,但这应该很容易。)