I am using quick_xml to deserialize some xml into their respective structs. I have implemented a enum variant and have implemented Deserialize myself for the enum. I would like to deserialize the enum based on the value in one of the tags inside the struct. The deserialized structs should contain this tag/value as an attribute as well. The limitation I have is that a deserializer does not implement copy or clone so I cannot use it to deserialize a struct more than once. The approach I have taken below is to deserialize the tag into a struct and then call deserialize based on the value of that tag which is obviously not working. Also, deserialize is derived for the structs I am trying to deserialize to.
Any suggestions/help on how to go about this would be greatly appreciated!
Here is a small snippet of the code implementing deserialize for my enum:
#[derive(Debug, PartialEq, Clone, Serialize)]
pub enum XMLDocumentVersion {
XMLDocumentVersion01(xml_document_version_01::XMLDocumentVersion01),
XMLDocumentVersion03(xml_document_version_03::XMLDocumentVersion03),
XMLDocumentVersion05(xml_document_version_05::XMLDocumentVersion05)
}
impl<'de> Deserialize<'de> for XMLDocumentVersion {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
struct Meta{
#[serde(
alias = "version",
deserialize_with = "deserialization_functions::string_is_capitalized_and_empty_string_is_none",
default
)]
version: Option<String>
}
let meta: Meta = Meta::deserialize(deserializer)?;
let version = meta.version;
if version.is_none(){
//deserialize using oldest schema version
let document = xml_document_version_01::XMLDocumentVersion01::deserialize(deserializer)?;
return Ok(XMLDocumentVersion::XMLDocumentVersion01(document));
}
else if let Some("01") = version.as_deref(){
let document = xml_document_version_01::XMLDocumentVersion01::deserialize(deserializer)?;
return Ok(XMLDocumentVersion::XMLDocumentVersion01(document));
}
else if let Some("03") = version.as_deref() {
let document = xml_document_version_03::XMLDocumentVersion03::deserialize(deserializer)?;
return Ok(XMLDocumentVersion::XMLDocumentVersion03(document));
}
// more code/cases...
else {
// don't have a variant for the schema version so deserialize using newest schema version
let document = xml_document_version_05::XMLDocumentVersion05::deserialize(deserializer)?;
return Ok(XMLDocumentVersion::XMLDocumentVersion05(document));
}
}
}
Here is a small sample xml sample/structure I am trying to deserialize to get the general idea. It is not the actual xml.
Variant 1:
<document>
<version>01</version>
<type>8</type>
<period>2021-12-21</period>
<issuer>
<id>7983</id>
<name>Jane Al</name>
<marker>JRJ</marker>
</issuer>
--...many more tags completely different from tags in other variant, different names and nesting structure
</document>
Variant 2:
<document>
<version>03</version>
<type>7</type>
<period>2021-12-21</period>
<alloc>rEsJ<alloc>
<issuer>
<id>7983</id>
<name>Jane Al</name>
<marker>JRJ</marker>
</issuer>
--...many more tags completely different from tags in other variant, different names and nesting structure
</document>
EDIT:
I got the idea to serialize to a basic struct and then conditionally deserialize. However, even deserializing to a basic structure is giving me errors. Here are 2 versions one with deserialize manually implemented and there other where it is derived:
This gives me error Some(Start)
#[derive(Debug, PartialEq, Clone, Serialize)]
struct Doc{
contents: String
}
impl<'de> Deserialize<'de> for Doc {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let val: String = String::deserialize(deserializer)?;
return Ok(Doc{contents: val});
}
}
let doc = Doc::deserialize(deserializer)?;
println!("{:?}", doc.clone());
let val = doc.contents;
This gives me error duplicate field \$value\
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
struct Doc{
#[serde(rename ="$value")]
contents: String
}
let doc = Doc::deserialize(deserializer)?;
println!("{:?}", doc.clone());
let val = doc.contents;