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

xml serde read translates optional attributes with value "" to None #671

Closed
francisdb opened this issue Oct 20, 2023 · 5 comments · Fixed by #672
Closed

xml serde read translates optional attributes with value "" to None #671

francisdb opened this issue Oct 20, 2023 · 5 comments · Fixed by #672
Assignees
Labels
bug serde Issues related to mapping from Rust types to XML

Comments

@francisdb
Copy link

francisdb commented Oct 20, 2023

If you want to be able to make a difference between attribute missing and attribute empty "" should serialize to Some("") but those attributes deserialize to None.
(useful for roundtrips where the output should be equal to input with small change applied)

use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
struct Name {
    #[serde(rename = "@first_name", skip_serializing_if = "Option::is_none")]
    first_name: Option<String>,
    #[serde(rename = "@second_name", skip_serializing_if = "Option::is_none")]
    second_name: Option<String>,
}

#[test]
fn read_and_write() {
    let expected = Name {
        first_name: Some("aaa".to_string()),
        second_name: Some("".to_string()),
    };

    let name =
        quick_xml::de::from_str::<Name>(r#"<Name first_name="aaa" second_name=""/>"#).unwrap();

    assert_eq!(expected, name);

    let s = quick_xml::se::to_string(&name).unwrap();

    assert_eq!(r#"<Name first_name="aaa" second_name=""/>"#, s);
}

fails with

thread 'read_and_write' panicked at tests/tezt.rs:21:5:
assertion `left == right` failed
  left: Name { first_name: Some("aaa"), second_name: Some("") }
 right: Name { first_name: Some("aaa"), second_name: None }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

I found similar issues that are marked as fixed: #252 and #527

@Mingun
Copy link
Collaborator

Mingun commented Oct 20, 2023

Yes, the problem only on Deserializer side, it is not tested in tests for #252. Probably should be an easy fix.

@Mingun Mingun added bug serde Issues related to mapping from Rust types to XML labels Oct 20, 2023
@Mingun Mingun self-assigned this Oct 20, 2023
@francisdb
Copy link
Author

If you want I can have a look at a PR this evening, however I see you self-assigned this?

@Mingun
Copy link
Collaborator

Mingun commented Oct 20, 2023

I'd looked at this. The current behavior was selected to match serde_json behavior which translates { "a": null } to a: None. In XML the closest analogues to null is empty value of attribute. But maybe we need to review this again.

@francisdb
Copy link
Author

Json { "a": "" } will probably give you a: Some("") which is similar to what this issue is going for?

The tricky part is that for json both { "a": null } and {} will return a: None so its impossible to do a round trip keeping exact equal representation. For xml there is no such issue.

@francisdb
Copy link
Author

Great, thanks @Mingun
I see a 0.31.0 release was made but it seems to be missing on crates.io?
https://crates.io/crates/quick-xml

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

Successfully merging a pull request may close this issue.

2 participants