quick-xml icon indicating copy to clipboard operation
quick-xml copied to clipboard

Use $value and $unflatten together

Open tyilo opened this issue 3 years ago • 1 comments

I have some XML that looks like:

<root>
  <state>B</state>
</root>

which I would like to represent in rust as:

enum State {
  A,
  B,
  C,
}

struct Root {
  state: State,
}

I have tried combining $unflatten and $value to make this happen, but it doesn't seem to work:

Cargo.toml:

[package]
name = "quick-xml-test"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0.139", features = ["derive"] }
quick-xml = { version = "0.23.0", features = ["serialize" ] }

src/main.rs:

mod working {
    use serde::{Deserialize, Serialize};

    #[derive(Debug, Deserialize, Serialize)]
    enum State {
        A,
        B,
        C,
    }

    #[derive(Debug, Deserialize, Serialize)]
    struct StateOuter {
        #[serde(rename = "$value")]
        state: State,
    }

    #[derive(Debug, Deserialize, Serialize)]
    pub struct Root {
        state: StateOuter,
    }
}

mod not_working {
    use serde::{Deserialize, Serialize};

    #[derive(Debug, Deserialize, Serialize)]
    #[serde(rename = "$value")]
    enum State {
        A,
        B,
        C,
    }

    #[derive(Debug, Deserialize, Serialize)]
    pub struct Root {
        #[serde(rename = "$unflatten=state")]
        state: State,
    }
}

fn main() {
    let xml = "<root><state>B</state></root>";
    println!("Deserialized (working): {:?}", quick_xml::de::from_str::<working::Root>(&xml));
    println!("Deserialized (not working): {:?}", quick_xml::de::from_str::<not_working::Root>(&xml));
}

Output:

Deserialized (working): Ok(Root { state: StateOuter { state: B } })
Deserialized (not working): Err(Custom("unknown variant `state`, expected one of `A`, `B`, `C`"))

Is it possible to do without introducing the extra StateOuter struct?

tyilo avatar Jul 19 '22 09:07 tyilo

$unflatten was a wrong feature, that is needed only for serializing and means forcely serialize field as an element (instead of attribute). I'll plan to remove it in next releases and made serialization-as-element to be a default and turning on serialization-as-attribute by a special mark.

As I said in #429, enums support leaves much to be desired. I wrote there how you can help.

Mingun avatar Jul 19 '22 15:07 Mingun