【问题标题】:Rust serde How deserialize xml "weird" lists?Rust serde 如何反序列化 xml “奇怪”列表?
【发布时间】:2020-12-07 03:33:15
【问题描述】:

我试图反序列化这种从技术上讲不是列表但行为类似的 xml 列表样式:

<list>
    <id-00001>
        <name type="string">Pedro</name>
        <age type="number">37</age>
    </id-00001>
    <id-00002>
        <name type="string">Alex</name>
        <age type="number">30</age>
    </id-00002>
<list>

“列表”上的项目数是可变的,只会增加id-0000x 上的数字(x)。

问题是我想不出如何使用 serde 将其映射到 Rust 结构。

我正在尝试做这样的事情:


#[derive(Debug, Default, Deserialize)]
#[serde(rename = "list")]
struct List {
    people: Vec<Person>
}

#[derive(Debug, Default, Deserialize)]
struct Person {
    name: String,
    age: u8
}

但我不知道如何处理id-0000x 标签。

编辑: 这是我使用的依赖项:

[dependencies]
serde = { version = "1.0.117", features = ["derive"] }
serde-xml-rs = "0.4.0"

提前感谢您的帮助。 问候

【问题讨论】:

  • 你需要的是解析器,而不是serde
  • 为什么age标签以prof结尾?
  • 能否请您指出一个解析器解决类似问题的示例?

标签: xml rust serde


【解决方案1】:

反序列化标签可能最简单:

struct List(BTreeMap<String, Person>);

这将为您提供有序的“id-bla”集合 => 人对。

【讨论】:

    【解决方案2】:

    感谢 Tomas Hurst 的建议,如果使用以下方法解决问题:

    use serde::{Deserialize, Deserializer}; // 1.0.94
    use serde_xml_rs;
    use std::collections::HashMap;
    
    const XML: &str = r#"
    <?xml version="1.0" encoding="utf-8"?>
    <root version="1">
        <list>
            <id-00001>
                <name type="string">Pedro</name>
                <age type="number">37</age>
            </id-00001>
            <id-00002>
                <name type="string">Alex</name>
                <age type="number">30</age>
            </id-00002>
        </list>
    </root>
    "#;
    
    #[derive(Debug, Default, Deserialize)]
    struct List {
        #[serde(deserialize_with = "deserialize_list")]
        list: Vec<Person>,
    }
    
    #[derive(Debug, Default, Deserialize, Clone)]
    struct Person {
        name: String,
        age: u8,
    }
    
    fn deserialize_list<'de, D>(d: D) -> Result<Vec<Person>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let people_raw: HashMap<String, Person> = Deserialize::deserialize(d)?;
        let people: Vec<Person> = people_raw.values().map(|person| person.clone()).collect();
        Ok(people)
    }
    
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let data: List = serde_xml_rs::from_str(XML)?;
        println!("{:?}", data);
        Ok(())
    }
    
    

    输出:

    List { list: [Person { name: "Pedro", age: 37 }, Person { name: "Alex", age: 30 }] }
    

    【讨论】:

    • 您可以使用 .cloned() 代替 .map(...),但最好是 .into_iter() 直接获取拥有的值。另请注意,使用 HashMap 会丢失排序,因此我使用 BTreeMap 按键排序。
    • 最后我不关心排序,我只想要数组,我会看看 in_iter 以避免复制。谢谢你的帮助!!
    猜你喜欢
    • 2021-08-28
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多