media-io / yaserde

Yet Another Serializer/Deserializer
MIT License
175 stars 57 forks source link

flatten and namespace confusion #126

Open kaedwen opened 2 years ago

kaedwen commented 2 years ago

I have small example with namespaces and the flatten feature. As soon as I use a flatten property inside a namespaced element the deserialization ends with an bad namespace error.

My struct layout follows the soap wsdl model generated with zeep-rs. The superfluous struct types are generated this way for some reason. Nevertheless the deserialize should work.

fn main() {

    env_logger::init();

    #[derive(Debug, Default, YaSerialize, YaDeserialize)]
    #[yaserde(namespace = "ns2: http://www.test.de/model/")]
    struct Paging {
        #[yaserde(prefix = "ns2")]
        pub offset: u32,
        #[yaserde(prefix = "ns2")]
        pub size: u32,
    }

    #[derive(Debug, Default, YaSerialize, YaDeserialize)]
    struct BodyWrapper {
        #[yaserde(flatten)]
        parameters: Body,
    }

    #[derive(Debug, Default, YaSerialize, YaDeserialize)]
    #[yaserde(
        namespace = "ns1: http://schemas.xmlsoap.org/soap/envelope/",
        prefix = "ns1"
    )]
    struct Body {
        #[yaserde(flatten)]
        pub paging: Paging,
        pub parameter1: String,
        pub parameter2: String,
    }

    type BodyWrapperType = BodyWrapper;

    #[derive(Debug, Default, YaSerialize, YaDeserialize)]
    #[yaserde(
        rename = "request",
        namespace = "ns1: http://schemas.xmlsoap.org/soap/envelope/",
        prefix = "ns1"
    )]
    struct Request {
        #[yaserde(prefix = "ns1")]
        pub body: BodyWrapperType,
    }

    let test = r#"
        <?xml version="1.0" encoding="utf-8"?>
        <ns1:request
            xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/"
            xmlns:ns2="http://www.test.de/model/">
            <ns1:body>
                <parameter1>get</parameter1>
                <parameter2>user</parameter2>
                <ns2:offset>0</ns2:offset>
                <ns2:size>10</ns2:size>
            </ns1:body>
        </ns1:request>
    "#;

    let data = yaserde::de::from_str::<Request>(&test);
    if let Ok(m) = data {
        println!("{:?}", m);
    } else {
        println!("{:?}", data.err());
    }
}
[2021-11-16T15:33:18Z DEBUG soap] Struct Request @ 0: start to parse "request"
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement({http://schemas.xmlsoap.org/soap/envelope/}ns1:request, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 1
[2021-11-16T15:33:18Z DEBUG soap] Struct BodyWrapper @ 1: start to parse "body"
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement({http://schemas.xmlsoap.org/soap/envelope/}ns1:body, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement(parameter1, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 3
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched Characters(get), new depth 3
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched EndElement(parameter1), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement(parameter2, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 3
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched Characters(user), new depth 3
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched EndElement(parameter2), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement({http://www.test.de/model/}ns2:offset, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 3
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched Characters(0), new depth 3
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched EndElement({http://www.test.de/model/}ns2:offset), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement({http://www.test.de/model/}ns2:size, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 3
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched Characters(10), new depth 3
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched EndElement({http://www.test.de/model/}ns2:size), new depth 2
[2021-11-16T15:33:18Z DEBUG soap] Struct Body @ 0: start to parse "body"
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement({http://schemas.xmlsoap.org/soap/envelope/}ns1:body, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 1
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement(parameter1, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched Characters(get), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched EndElement(parameter1), new depth 1
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement(parameter2, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched Characters(user), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched EndElement(parameter2), new depth 1
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement({http://www.test.de/model/}ns2:offset, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched Characters(0), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched EndElement({http://www.test.de/model/}ns2:offset), new depth 1
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched StartElement({http://www.test.de/model/}ns2:size, {"": "", "ns1": "http://schemas.xmlsoap.org/soap/envelope/", "ns2": "http://www.test.de/model/", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched Characters(10), new depth 2
[2021-11-16T15:33:18Z DEBUG yaserde::de] Fetched EndElement({http://www.test.de/model/}ns2:size), new depth 1
[2021-11-16T15:33:18Z DEBUG soap] Struct Paging @ 0: start to parse "body"
Some("bad namespace for body, found http://schemas.xmlsoap.org/soap/envelope/")

If a comment out the flattened Paging element in the Body struct the deserialization succeeds.

Christian-Achilli commented 1 year ago

I have solved it by manually flattening the structs. In your case, You may have to change the Body to be something like this (untested):

    #[derive(Debug, Default, YaSerialize, YaDeserialize)]
    #[yaserde(
        namespace = "ns1: http://schemas.xmlsoap.org/soap/envelope/",
        prefix = "ns1"
    )]
    struct Body {
        #[yaserde(prefix = "ns2", namespace = "ns2: http://www.test.de/model/"))]
        pub offset: u32,
        #[yaserde(prefix = "ns2", namespace = "ns2: http://www.test.de/model/"))]
        pub size: u32,
        pub parameter1: String,
        pub parameter2: String,
    }