Skip to content

Commit

Permalink
Restore ability to deserialize attributes that represents XML namespa…
Browse files Browse the repository at this point in the history
…ce mappings (`xmlns:xxx`)
  • Loading branch information
Mingun authored and dralley committed Jan 6, 2023
1 parent 4a09041 commit 967d60d
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 5 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ name = "serde-migrated"
required-features = ["serialize"]
path = "tests/serde-migrated.rs"

[[test]]
name = "serde-issues"
required-features = ["serialize"]
path = "tests/serde-issues.rs"

[[test]]
name = "async-tokio"
required-features = ["async-tokio"]
Expand Down
6 changes: 6 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@

### Bug Fixes

- [#537]: Restore ability to deserialize attributes that represents XML namespace
mappings (`xmlns:xxx`) that was broken since [#490]

### Misc Changes

[#490]: https://github.com/tafia/quick-xml/pull/490
[#537]: https://github.com/tafia/quick-xml/issues/537

## 0.27.1 -- 2022-12-28

### Bug Fixes
Expand Down
14 changes: 11 additions & 3 deletions src/de/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ fn decode_name<'n>(name: QName<'n>, decoder: Decoder) -> Result<Cow<'n, str>, De
/// Converts a name to an identifier string using the following rules:
///
/// - if it is an [`attribute`] name, put `@` in front of the identifier
/// - if it is a namespace binding (`xmlns` or `xmlns:xxx`) put the decoded name
/// to the identifier
/// - put the decoded [`local_name()`] of a name to the identifier
///
/// The final identifier looks like `[@]local_name`
/// The final identifier looks like `[@]local_name`, or `@xmlns`, or `@xmlns:binding`
/// (where `[]` means optional element).
///
/// The deserializer also supports deserializing names as other primitive types:
Expand Down Expand Up @@ -72,10 +74,16 @@ pub struct QNameDeserializer<'d> {
impl<'d> QNameDeserializer<'d> {
/// Creates deserializer from name of an attribute
pub fn from_attr(name: QName<'d>, decoder: Decoder) -> Result<Self, DeError> {
let local = decode_name(name, decoder)?;
// https://github.com/tafia/quick-xml/issues/537
// Namespace bindings (xmlns:xxx) map to `@xmlns:xxx` instead of `@xxx`
let field = if name.as_namespace_binding().is_some() {
decoder.decode(name.into_inner())?
} else {
decode_name(name, decoder)?
};

Ok(Self {
name: Cow::Owned(format!("@{local}")),
name: Cow::Owned(format!("@{field}")),
})
}

Expand Down
4 changes: 2 additions & 2 deletions tests/issues.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Regression tests found in various issues
//! Regression tests found in various issues.
//!
//! Name each test as `issue<GH number>`
//! Name each module / test as `issue<GH number>` and keep sorted by issue number
use quick_xml::events::{BytesStart, Event};
use quick_xml::reader::Reader;
Expand Down
60 changes: 60 additions & 0 deletions tests/serde-issues.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//! Regression tests found in various issues with serde integration.
//!
//! Name each module / test as `issue<GH number>` and keep sorted by issue number
use quick_xml::de::from_str;
use quick_xml::se::to_string;
use serde::{Deserialize, Serialize};

/// Regression test for https://github.com/tafia/quick-xml/issues/537.
///
/// This test checks that special `xmlns:xxx` attributes uses full name of
/// an attribute (xmlns:xxx) as a field name instead of just local name of
/// an attribute (xxx)
mod issue537 {
use super::*;
use pretty_assertions::assert_eq;

#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct Bindings<'a> {
/// Default namespace binding
#[serde(rename = "@xmlns")]
xmlns: &'a str,

/// Named namespace binding
#[serde(rename = "@xmlns:named")]
xmlns_named: &'a str,

/// Usual attribute
#[serde(rename = "@attribute")]
attribute: &'a str,
}

#[test]
fn de() {
assert_eq!(
from_str::<Bindings>(
r#"<Bindings xmlns="default" xmlns:named="named" attribute="attribute"/>"#
)
.unwrap(),
Bindings {
xmlns: "default",
xmlns_named: "named",
attribute: "attribute",
}
);
}

#[test]
fn se() {
assert_eq!(
to_string(&Bindings {
xmlns: "default",
xmlns_named: "named",
attribute: "attribute",
})
.unwrap(),
r#"<Bindings xmlns="default" xmlns:named="named" attribute="attribute"/>"#
);
}
}

0 comments on commit 967d60d

Please sign in to comment.