-
Notifications
You must be signed in to change notification settings - Fork 224
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
serde untagged enums are broken #203
Comments
As of now, it is working for me with Deserialize (here) but it remains incapable to Serialize, it omits the untagged field on write. |
Thanks for commenting it! |
It turned out that my untagged enum was being serialized, just not as an attribute (as I wanted). I think this is the expected behavior, so this is solved from my side. Enum as attributeI am not sure if there is something more straight forward that I'm missing, but this solved the enum as attribute problem for me. <root kind="calamari" sense="whatever"/> Structs and enums definitions: use serde::{Deserialize, Serialize, Serializer};
#[derive(Deserialize, Serialize)]
struct Root {
kind: A,
sense: String,
}
// do not derive `Serialize`!
#[derive(Deserialize)]
#[serde(untagged)]
enum A {
NestedEnum(B),
Other(String)
}
#[derive(Deserialize, Serialize)]
#[serde(rename_all="camelCase")]
enum B {
Calamari,
Tortoise,
Octopus
} Serialize implementation (for the nested enum, a macro can be used like this one): impl Serialize for A {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::NestedEnum(ref b) => serializer.serialize_str(match b {
B::Calamari => "calamari", // in lower case for my specific case
B::Tortoise => "tortoise",
B::Octopus => "octopus",
}
),
Self::Other(s) => serializer.serialize_str(s),
}
}
} |
The sample code at the top of this issue still fails to match the |
Attributes seem to deserialize successfully. Elements fail! |
Actually, OP's example succeeds with I'll have to investigate further why my code is hitting this error. |
Found my issue. It's related to vector, or optional vector fields: use serde::Deserialize;
fn main() {
let bs = br###"
<Xs x_id="bla">
<st>
<v id="some_id">some_s</v>
</st>
</Xs>
"###;
// works as expected with 0, 1, or more `v` elements
let xs: Xs = quick_xml::de::from_reader(&bs[..]).unwrap();
eprintln!("{:#?}", xs);
let bn = br###"
<Xn x_id="bla">
<en>
<v id="some_id">some_s</v>
</en>
</Xn>
"###;
// fails with 1 or more `v` elements
let xn: Xn = quick_xml::de::from_reader(&bn[..]).unwrap();
eprintln!("{:#?}", xn);
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)] // TODO: remove after some tests
struct SWithId {
id: String,
#[serde(rename="$value")]
s: String,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)] // TODO: remove after some tests
#[serde(untagged)]
enum En {
S{
s: String,
},
V{
//v: Option<SWithId>, // works
//v: Vec<SWithId>, // fails
v: Option<Vec<SWithId>>, // fails
},
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)] // TODO: remove after some tests
struct St {
// v: Vec<SWithId>, // works
v: Option<Vec<SWithId>>, // works
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Xn {
x_id: String,
en: Option<En>,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Xs {
x_id: String,
st: Option<St>,
} Should I create a new issue? |
@MoSal, your last problem is the serde restriction due to serde-rs/serde#1183. <Xn x_id="bla">
<en>
<v id="some_id">some_s</v>
</en>
</Xn> generically deserialized into Content::Map {
Content::String("x_id") => Content::String("bla"),
Content::String("en") => Content::Map {
Content::String("v") => Content::Map {
Content::String("id") => Content::String("some_id"),
Content::String("$value") => Content::String("some_s"),
},
},
}
In XML we cannot distinguish between an array and a single element when there is only one element, because arrays has no special syntax in XML. So your problem is unsolvable using that types. Avoid using untagged enums, internally tagged enums, |
@benkay86 , your case not work for the same reason, but more tricky. While #[derive(Debug, Deserialize, PartialEq)]
struct AB {
a: String,
b: String,
}
#[derive(Debug, Deserialize, PartialEq)]
struct X2 {
y: AB,
}
let xml_data = r#"
<x>
<y>
<a>The letter a.</a>
<b>The letter b.</b>
</y>
</x>
"#;
let x: X2 = quick_xml::de::from_str(xml_data).unwrap();
assert_eq!(x, X2 { y: AB {
a: "The letter a.".to_string(),
b: "The letter b.".to_string(),
}}); works fine, untagged enums will not work due to serde-rs/serde#1183.
I close this, because we cannot do anything with that at quick-xml level. |
quick-xml is an great crate, and being able to use it with serde would be just amazing! It looks like there are a few issues already open with regard to buggy serde support, namely #185 and #190. This issue is probably related.
Unless I have misunderstood how enums are supposed to work, serde support for deserializing untagged enums appears to be broken:
In fairness, this does not work in serde-xml-rs either.
For others who may be reading this issue looking for a quick solution, I am using the following ugly hack as a workaround. Improvements are welcome.
The text was updated successfully, but these errors were encountered: