【问题标题】:Parse XML tag with multiple possible types [Rust, serde, serde-xml-rs]解析具有多种可能类型的 XML 标记 [Rust、serde、serde-xml-rs]
【发布时间】:2021-10-04 11:55:51
【问题描述】:

我想解析一个可能包含不同数据类型的 XML 元素。

以下是我能想到的最简单的情况:

use serde_derive::{Deserialize, Serialize};
use serde_xml_rs::{from_str};

const XML: &str = r#"
<element>
    foo
</element>
"#;
const XML2: &str = r#"
<element>
    123
</element>
"#;

#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Element {
    #[serde(rename="element")]
    Text(String),
    #[serde(rename="element")]
    Number(i32),
}

fn main() {
    let el: Element = from_str(&XML).unwrap();
    println!("{:?}", &el);
    println!("\n\n\n\n");
    let el2: Element = from_str(&XML2).unwrap();
    println!("{:?}", &el2);
}

当前代码将这两个元素分别解析为 Text(String),而不是 Text(String)、Number(i32)。

如果我颠倒顺序,程序就会崩溃,因为“foo”不能被解析为整数。

#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Element {
    #[serde(rename="element")]
    Number(i32),
    #[serde(rename="element")]
    Text(String),
}

如何正确实施我的程序?

【问题讨论】:

    标签: xml rust serde


    【解决方案1】:

    如果我正确理解您的帖子,则只要值可以解析为 i32Text 否则您需要 Number。你可以使用FromStr trait 来实现它。

    #[derive(Serialize, serde_with::DeserializeFromStr, Debug, PartialEq)]
    enum Element {
        #[serde(rename="element")]
        Text(String),
        #[serde(rename="element")]
        Number(i32),
    }
    
    impl std::str::FromStr for Element {
        type Err = std::convert::Infallible;
        
        fn from_str(s: &str) -> Result<Self, Self::Err> {
            if let Ok(i) = s.parse::<i32>() {
                Ok(Element::Number(i))
            } else {
                Ok(Element::Text(s.to_string()))
            }
        }
    }
    

    【讨论】:

    • 当 Number(i32) 是一个结构时,我该怎么做呢?例如:struct SubElement { id: i32 }
    • 您的意思是在枚举定义中使用Number(SubElement) 而不是Number(i32)?在这种情况下,您可以在FromStr 中返回Ok(Element::Number(SubElement{ id: i }))
    • 不,我的意思是在enum 之外定义的struct SubElement{ id: i32 }。所以枚举的选项是Text(String)SubElementXML2 将是 &lt;element&gt;&lt;subelement id="123"&gt;&lt;/subelement&gt;&lt;/element&gt;
    • 你的Element 枚举只有一个变体,比如enum Element { Text(String) }?您不能从同一个函数返回两种不同的类型。您需要将它们放入一个新的枚举中,该枚举具有ElementSubElement 的变体,或者执行类型擦除并返回装箱值。如果我误解了您的问题,也许可以提出一个新问题。
    • 我开始了一个新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 2022-08-15
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多