I want to parse an XML element that may contain different data types.
The following is the most simple case I could think of:
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);
}
The current code parses both elements as Text(String), instead of Text(String), Number(i32) respectively.
If I reverse the order the program crashes, because "foo" cannot be parsed as integer.
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Element {
#[serde(rename="element")]
Number(i32),
#[serde(rename="element")]
Text(String),
}
How can I correctly implement my program?
CodePudding user response:
If I understand your post correctly, you want Number
whenever the value can be parsed as a i32
and Text
otherwise. You can implement that using the 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()))
}
}
}