Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using flatten and rename="$value" on adjacent fields causes error #326

Open
ch1nq opened this issue Oct 11, 2021 · 1 comment
Open

Using flatten and rename="$value" on adjacent fields causes error #326

ch1nq opened this issue Oct 11, 2021 · 1 comment
Labels
bug serde Issues related to mapping from Rust types to XML

Comments

@ch1nq
Copy link

ch1nq commented Oct 11, 2021

I have an issue similar to this issue in serde-xml-rs.

I have the following implementation, where i use flatten and rename="$value" on fields in the same struct:

use serde::Deserialize;
use quick_xml::de;

#[derive(Debug, Deserialize)]
struct ParentStruct {
    #[serde(flatten)]
    flat_struct: FlatStruct,
    #[serde(rename = "$value")]
    children: Vec<ChildStruct>,
}

#[derive(Debug, Deserialize)]
struct FlatStruct {
    a: String,
    b: String,
}

#[derive(Debug, Deserialize)]
struct ChildStruct {
    c: String,
    d: String,
}

fn main() {
    let xml = r##"
        <ParentStruct a="1" b="2">
            <ChildStruct c="3" d="4"/>
            <ChildStruct c="5" d="6"/>
        </ParentStruct>
    "##;

    let parent_struct: ParentStruct = de::from_str(xml).unwrap();
    dbg!(parent_struct);
}

I expect to get a struct similar to:

ParentStruct {
    flat_struct: FlatStruct {
        a: "1",
        b: "2",
    },
    children: [
        ChildStruct {
            c: "3",
            d: "4",
        },
        ChildStruct {
            c: "5",
            d: "6",
        },
    ],
}

But I get the following error:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom("missing field `$value`")'

Using flatten or rename="$value" in isolation works perfectly, but the combination of the two seems to cause the error.

Is this a bug, or am I somehow using these macros wrong?

@Mingun Mingun added bug serde Issues related to mapping from Rust types to XML labels May 21, 2022
@Mingun
Copy link
Collaborator

Mingun commented Oct 29, 2022

@askepen, actually, your example is working since merging #490 after few changes:

  • attributes should have names started with @
  • $value special not is not required here
#[test]
fn issue326() {
    #[derive(Debug, Deserialize, PartialEq)]
    struct ParentStruct {
        #[serde(flatten)]
        flat_struct: FlatStruct,

        #[serde(rename = "ChildStruct")]
        children: Vec<ChildStruct>,
    }

    #[derive(Debug, Deserialize, PartialEq)]
    struct FlatStruct {
        #[serde(rename = "@a")]
        a: String,
        #[serde(rename = "@b")]
        b: String,
    }

    #[derive(Debug, Deserialize, PartialEq)]
    struct ChildStruct {
        #[serde(rename = "@c")]
        c: String,
        #[serde(rename = "@d")]
        d: String,
    }

    assert_eq!(
        from_str::<ParentStruct>(
            r#"
            <ParentStruct a="1" b="2">
                <ChildStruct c="3" d="4"/>
                <ChildStruct c="5" d="6"/>
            </ParentStruct>
            "#
        )
        .unwrap(),
        ParentStruct {
            flat_struct: FlatStruct {
                a: "1".to_string(),
                b: "2".to_string(),
            },
            children: vec![
                ChildStruct {
                    c: "3".to_string(),
                    d: "4".to_string(),
                },
                ChildStruct {
                    c: "5".to_string(),
                    d: "6".to_string(),
                },
            ],
        }
    );
}

But I leave this bug open, because you spot a problem, that really exists:

#[test]
fn issue326_enum() {
    #[derive(Debug, Deserialize, PartialEq)]
    struct ParentStruct {
        #[serde(flatten)]
        flat_struct: FlatStruct,

        #[serde(rename = "$value")]
        children: Vec<Enum>,
    }

    #[derive(Debug, Deserialize, PartialEq)]
    struct FlatStruct {
        #[serde(rename = "@a")]
        a: String,
        #[serde(rename = "@b")]
        b: String,
    }

    #[derive(Debug, Deserialize, PartialEq)]
    enum Enum {
        ChildStruct {
            #[serde(rename = "@c")]
            c: String,
            #[serde(rename = "@d")]
            d: String,
        }
    }

    // Result:
    // thread 'issue326_enum' panicked at 'called `Result::unwrap()` on an `Err` value: Custom("missing field `$value`")', 
    assert_eq!(
        from_str::<ParentStruct>(
            r#"
            <ParentStruct a="1" b="2">
                <ChildStruct c="3" d="4"/>
                <ChildStruct c="5" d="6"/>
            </ParentStruct>
            "#
        )
        .unwrap(),
        ParentStruct {
            flat_struct: FlatStruct {
                a: "1".to_string(),
                b: "2".to_string(),
            },
            children: vec![
                Enum::ChildStruct {
                    c: "3".to_string(),
                    d: "4".to_string(),
                },
                Enum::ChildStruct {
                    c: "5".to_string(),
                    d: "6".to_string(),
                },
            ],
        }
    );
}

Problem disappeared after commenting out the flat_struct field. I don't known, although, if it would be possible to fix the issue on the quick-xml side. serde(flatten) issues usually due serde-rs/serde#1183

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug serde Issues related to mapping from Rust types to XML
Projects
None yet
Development

No branches or pull requests

2 participants