0
votes

How can I deserialize an XML-string (using serde derive) returned by an API that might have different children?

If I call an API it might return one of the following result sets:

use serde::Deserialize;
use serde_xml_rs::from_str;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Error {
    code: u32,
    message: String,
}

#[derive(Debug, Deserialize)]
struct Item {
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct DataSet {
    error: Option<Error>,

    data: Option<Vec<Item>>
}

fn main() {
    let error = r#"
    <DataSet>
        <Error>
            <Code>0</Code>
            <Message>error</Message>
        </Error>
    </DataSet>
    "#;

    let dataset: DataSet = from_str(error).unwrap();
    println!("{:#?}", dataset);

    let items = r#"
    <DataSet>
        <Item>..</Item>
        <Item>..</Item>
    </DataSet>
"#;

    let dataset: DataSet = from_str(items).unwrap();
    println!("{:#?}", dataset);
}
[package]
name = "dataset"
version = "0.1.0"
edition = "2018"

[dependencies]
serde = { version = "1", features = ["derive"] }
serde-xml-rs = "0.3"

But I feel like there should be a more idiomatic way of achieving this. Especially since it would make matching off the data a lot easier.

I've tried using #[serde(flatten)], and I've tried setting ApiResponse to a tuple-struct and a struct with a single tuple parameter. No luck.

Is this possible without having to build a custom deserializer?

1
The answer is simple but serde-xml-rs have bugs - Stargateur

1 Answers

0
votes

Take a look at some of the serde examples which might be able to help you here. Specifically the examples/docs on untagged enums which allow you to define many ways to deserialize into a single enum type.