media-io / yaserde

Yet Another Serializer/Deserializer
MIT License
174 stars 58 forks source link

Deserialization of elements yields elements not in explicitly specified namespace #157

Open riverar opened 1 year ago

riverar commented 1 year ago

When deserializing xml into structures with yaserde namespace attributes affixed, I am seeing deserialized elements that do not belong in the specified namespace.

Example below.

cargo.toml

[package]
name = "app"
version = "0.0.0"
edition = "2018"
publish = false

[dependencies]
yaserde = "0.8.0"
yaserde_derive = "0.8.0"

main.rs

use yaserde_derive::YaDeserialize;

#[derive(YaDeserialize, Debug)]
#[yaserde(namespace = "aaa")]
struct Root
{
    #[yaserde(rename = "Child")]
    children: Vec<Child>
}

#[derive(YaDeserialize, Debug)]
#[yaserde(namespace = "aaa")]
struct Child
{
    #[yaserde(attribute)]
    a: String
}

fn main()
{    
    let xml = r#"
        <Root xmlns="aaa" xmlns:bbb="bbb">
            <Child a="1" />
            <Child a="2" />
            <bbb:Child a="42" />
        </Root>
        "#;

    let doc = yaserde::de::from_str::<Root>(xml).unwrap();
    dbg!(doc);
}

output

[src\main.rs:30] doc = Root {
    children: [
        Child {
            a: "1",
        },
        Child {
            a: "2",
        },
        Child {
            a: "42",
        },
    ],
}

I did not expect <bbb:Child a="42" /> to deserialize or show up in the result set.

MarcAntoine-Arnaud commented 1 year ago

Hello @riverar,

You have to understood YaSerDe works quasi like XML. namespace defines a list of namespaces. In addition, the prefix will said which namespace will be used.

So try something like:

use yaserde_derive::YaDeserialize;

#[derive(YaDeserialize, Debug)]
#[yaserde(
  prefix = "aaa",
  namespace = "aaa"
)]
struct Root
{
    #[yaserde(rename = "Child", prefix = "aaa")]
    children: Vec<Child>
}

#[derive(YaDeserialize, Debug)]
#[yaserde(
  prefix = "aaa",
  namespace = "aaa"
)]
struct Child
{
    #[yaserde(attribute, prefix = "aaa")]
    a: String
}

maybe the difference is the usage of default prefix. Where with YaSerDe all namespaces requires to be mentioned to constraint.

riverar commented 1 year ago

Hey @MarcAntoine-Arnaud, thanks for the quick reply. Your sample still captures the <bbb:Child a="42" />.

Here's the runnable version:

use yaserde_derive::YaDeserialize;

#[derive(YaDeserialize, Debug)]
#[yaserde(
  namespace = "aaa"
)]
struct Root
{
    #[yaserde(rename = "Child", prefix = "aaa")]
    children: Vec<Child>
}

#[derive(YaDeserialize, Debug)]
#[yaserde(
  prefix = "aaa",
  namespace = "aaa"
)]
struct Child
{
    #[yaserde(attribute, prefix = "aaa")]
    a: String
}

fn main()
{    
    let xml = r#"
        <Root xmlns="aaa" xmlns:bbb="bbb">
            <Child a="1" />
            <Child a="2" />
            <bbb:Child a="42" />
        </Root>
        "#;

    let doc = yaserde::de::from_str::<Root>(xml).unwrap();
    dbg!(doc);
}
MarcAntoine-Arnaud commented 1 year ago

it seems a conflict between namespace matching. Very good and deep case !