Skip to content

Commit

Permalink
feat: handle same field name but different namespace
Browse files Browse the repository at this point in the history
issue #186
  • Loading branch information
MarcAntoine-Arnaud committed Aug 31, 2024
1 parent e4aff84 commit a067b85
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 8 deletions.
6 changes: 3 additions & 3 deletions examples/src/bbigras_namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use yaserde::*;
namespace = "html: http://www.w3.org/TR/REC-html40"
)]
struct Workbook {
#[yaserde(rename = "Worksheet")]
#[yaserde(rename = "Worksheet", prefix = "ss")]
worksheet: Worksheet,
}

Expand All @@ -23,7 +23,7 @@ struct Workbook {
namespace = "html: http://www.w3.org/TR/REC-html40"
)]
struct Worksheet {
#[yaserde(rename = "Table")]
#[yaserde(rename = "Table", prefix = "ss")]
table: Table,
#[yaserde(attribute, rename = "Name", prefix = "ss")]
ws_name: String,
Expand Down Expand Up @@ -53,7 +53,7 @@ struct Table {
#[yaserde(attribute, rename = "DefaultRowHeight", prefix = "ss")]
default_column_height: f32,

#[yaserde(rename = "Row")]
#[yaserde(rename = "Row", prefix = "ss")]
rows: Vec<Row>,
}

Expand Down
2 changes: 2 additions & 0 deletions examples/src/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ where
}

#[derive(YaSerialize, YaDeserialize, Debug, Default, Clone, Eq, PartialEq)]
#[yaserde(namespace = "u: urn:schemas-upnp-org:service:AVTransport:1")]
pub struct SoapPlay {
#[yaserde(rename = "Play", prefix = "u", default)]
pub body: Play,
Expand Down Expand Up @@ -93,6 +94,7 @@ fn test_for_generic_nested_struct() {
};

let s = ser::to_string(&a).unwrap();
println!("{s}");
let b: SoapEnvelope<SoapPlay> = de::from_str(&s).unwrap();

assert_eq!(a, b);
Expand Down
1 change: 1 addition & 0 deletions examples/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ mod bbigras_namespace;
mod boscop;
mod generic;
mod ln_dom;
mod same_element_different_namespaces;
mod svd;
37 changes: 37 additions & 0 deletions examples/src/same_element_different_namespaces.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// related to issue https://github.com/media-io/yaserde/issues/186
use yaserde::*;

#[derive(YaDeserialize, Debug, PartialEq)]
#[yaserde(
namespace = "myns: http://my_namespace_1/",
namespace = "ext: http://my_namespace_2/",
prefix = "myns"
)]
pub struct ErrorType {
#[yaserde(rename = "reasonCode", prefix = "myns")]
pub reason_code: Option<u16>,
#[yaserde(rename = "reasonCode", prefix = "ext")]
pub ext_reason_code: Option<u16>,
}

#[test]
fn same_element_different_namespaces() {
use yaserde::de::from_str;

let content = r#"
<error_type xmlns="http://my_namespace_1/" xmlns:ext="http://my_namespace_2/">
<reasonCode>12</reasonCode>
<ext:reasonCode>32</ext:reasonCode>
</error_type>
"#;

let loaded: ErrorType = from_str(content).unwrap();
println!("{:?}", loaded);

let reference = ErrorType {
reason_code: Some(12),
ext_reason_code: Some(32),
};

assert_eq!(loaded, reference);
}
26 changes: 24 additions & 2 deletions yaserde_derive/src/common/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ impl YaSerdeField {
},
);

let prefix = self
.attributes
.prefix
.clone()
.map(|p| format!("{}_", p.to_upper_camel_case()))
.unwrap_or_default();

let attribute = self
.attributes
.attribute
Expand All @@ -98,7 +105,8 @@ impl YaSerdeField {

Ident::new(
&format!(
"__Visitor_{attribute}{}_{}",
"__Visitor_{attribute}{}{}_{}",
prefix,
label.replace('.', "_").to_upper_camel_case(),
struct_id
),
Expand Down Expand Up @@ -130,6 +138,20 @@ impl YaSerdeField {
.map(|skip_serializing_if| Ident::new(skip_serializing_if, self.get_span()))
}

pub fn prefix_namespace(&self, root_attributes: &YaSerdeAttribute) -> String {
root_attributes
.namespaces
.iter()
.find_map(|(prefix, namespace)| {
if self.attributes.prefix.eq(prefix) {
Some(namespace.clone())
} else {
None
}
})
.unwrap_or_default()
}

pub fn get_namespace_matching(
&self,
root_attributes: &YaSerdeAttribute,
Expand Down Expand Up @@ -261,7 +283,7 @@ impl From<&syn::PathSegment> for Field {
return Field::from(&path.path);
}
Some(syn::GenericArgument::Type(syn::Type::Group(syn::TypeGroup { elem, .. }))) => {
if let syn::Type::Path(ref group) = elem.as_ref() {
if let Path(ref group) = elem.as_ref() {
return Field::from(&group.path);
}
}
Expand Down
12 changes: 9 additions & 3 deletions yaserde_derive/src/de/expand_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,11 @@ pub fn parse(
let value_label = field.get_value_label();
let label_name = field.renamed_label_without_namespace();

let namespace = field.prefix_namespace(root_attributes);

let visit_struct = |struct_name: syn::Path, action: TokenStream| {
Some(quote! {
#label_name => {
(#namespace, #label_name) => {
if depth == 0 {
// Don't count current struct's StartElement as substruct's StartElement
let _root = reader.next_event();
Expand Down Expand Up @@ -423,7 +425,9 @@ pub fn parse(
let event = reader.next_event()?;
#write_unused
} else {
match name.local_name.as_str() {
let namespace = name.namespace.clone().unwrap_or_default();

match (namespace.as_str(), name.local_name.as_str()) {
#call_visitors
_ => {
let event = reader.next_event()?;
Expand Down Expand Up @@ -493,8 +497,10 @@ fn build_call_visitor(
quote!(name.local_name.as_str()),
);

let namespace = field.prefix_namespace(root_attributes);

Some(quote! {
#label_name => {
(#namespace, #label_name) => {
let visitor = #visitor_label{};

#namespaces_matching
Expand Down

0 comments on commit a067b85

Please sign in to comment.