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

Inconsistent namespace stripping with serde

Open rijenkii opened this issue 4 years ago • 1 comments

Example:

<ns:list ns:value="hello">
    <ns:item ns:value="world!"/>
</ns:list>

To correctly serialize/deserialize this document, I have to create following structs:

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename = "ns:list")]
struct List {
    #[serde(rename = "ns:value")]
    value: String,
    #[serde(rename(deserialize = "value", serialize = "ns:value"))]
    items: Vec<Item>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Item {
    #[serde(rename = "ns:value")]
    value: String,
}

Only if I put all these seemingly random attributes, result of serialization is exact same as original document. And while I understand why I need to put rename on the root element and why on the child elements it does nothing, I do not understand why I need this explicit separation of deserialize and serialize renames for the items field. quick-xml seems to strip namespaces from the tag names when deserializing, which it does not do for attributes, and it makes for a very annoying "dance" with these renames.

rijenkii avatar Dec 28 '21 17:12 rijenkii

Also, because of namespace stripping, it is currently impossible to deserialize following xml:

<list>
    <ns1:item value="hello" />
    <ns2:item value=123 />
</list>

Naive approach does not work, as expected:

#[derive(Debug, serde::Deserialize)]
#[serde(rename = "list")]
struct List {
    #[serde(rename = "ns1:item")]
    item1s: Vec<Item1>,
    #[serde(rename = "ns2:item")]
    item2s: Vec<Item2>,
}

#[derive(Debug, serde::Deserialize)]
struct Item1 {
    value: String,
}

#[derive(Debug, serde::Deserialize)]
struct Item2 {
    value: u32,
}

fn main() {
    let xml = r#"<list><ns1:item value="hello"/><ns2:item value="123"/></list>"#;
    println!("{:#?}", quick_xml::de::from_str::<List>(xml).unwrap());
}
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom("missing field `ns1:item`")', src/main.rs:22:60
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

NOTE: It is entierly possible that I am missing something obvious and there is a simple solution to this.

rijenkii avatar Dec 29 '21 02:12 rijenkii