Correctly add namespaced attributes to elements

Eijebong created

Instead of adding the local_name of an attribute, if a prefix exists,
add prefix:local_name to allow users to retrieve it via the namespaced
key name.

For example, with this XML:
```
<?xml version="1.0" encoding="utf-8"?>
<root xml:lang="en" >
</root>
```

`root.attr("xml:lang").unwrap()` will now correctly return "en".
`root.attr("lang")` will not retrieve "xml:lang" value anymore.

This is a breaking change.

Fixes #2

Change summary

src/element.rs | 21 +++++++++++++++++++--
src/tests.rs   | 12 +++++++++++-
2 files changed, 30 insertions(+), 3 deletions(-)

Detailed changes

src/element.rs 🔗

@@ -197,7 +197,15 @@ impl Element {
             match e {
                 ReaderEvent::StartElement { name, attributes, namespace } => {
                     let attributes = attributes.into_iter()
-                                               .map(|o| Attribute::new(o.name.local_name, o.value))
+                                               .map(|o| {
+                                                    Attribute::new(
+                                                        match o.name.prefix {
+                                                            Some(prefix) => format!("{}:{}", prefix, o.name.local_name),
+                                                            None => o.name.local_name
+                                                        },
+                                                        o.value
+                                                    )
+                                                })
                                                .collect();
                     let ns = if let Some(ref prefix) = name.prefix {
                         namespace.get(prefix)
@@ -205,6 +213,7 @@ impl Element {
                     else {
                         namespace.get(NS_NO_PREFIX)
                     }.map(|s| s.to_owned());
+
                     let mut root = Element::new(name.local_name, ns, attributes, Vec::new());
                     root.from_reader_inner(reader)?;
                     return Ok(root);
@@ -223,7 +232,15 @@ impl Element {
             match e {
                 ReaderEvent::StartElement { name, attributes, namespace } => {
                     let attributes = attributes.into_iter()
-                                               .map(|o| Attribute::new(o.name.local_name, o.value))
+                                               .map(|o| {
+                                                    Attribute::new(
+                                                        match o.name.prefix {
+                                                            Some(prefix) => format!("{}:{}", prefix, o.name.local_name),
+                                                            None => o.name.local_name
+                                                        },
+                                                        o.value
+                                                    )
+                                                })
                                                .collect();
                     let ns = if let Some(ref prefix) = name.prefix {
                         namespace.get(prefix)

src/tests.rs 🔗

@@ -7,11 +7,12 @@ use xml::writer::EventWriter;
 
 use element::Element;
 
-const TEST_STRING: &'static str = r#"<?xml version="1.0" encoding="utf-8"?><root xmlns="root_ns" a="b">meow<child c="d" /><child xmlns="child_ns" d="e" />nya</root>"#;
+const TEST_STRING: &'static str = r#"<?xml version="1.0" encoding="utf-8"?><root xmlns="root_ns" xml:lang="en" a="b">meow<child c="d" /><child xmlns="child_ns" d="e" xml:lang="fr" />nya</root>"#;
 
 fn build_test_tree() -> Element {
     let mut root = Element::builder("root")
                            .ns("root_ns")
+                           .attr("xml:lang", "en")
                            .attr("a", "b")
                            .build();
     root.append_text_node("meow");
@@ -22,6 +23,7 @@ fn build_test_tree() -> Element {
     let other_child = Element::builder("child")
                               .ns("child_ns")
                               .attr("d", "e")
+                              .attr("xml:lang", "fr")
                               .build();
     root.append_child(other_child);
     root.append_text_node("nya");
@@ -94,3 +96,11 @@ fn namespace_propagation_works() {
                    .get_child("grandchild", "root_ns").unwrap()
                    .ns(), root.ns());
 }
+
+#[test]
+fn namespace_attributes_works() {
+    let mut reader = EventReader::new(Cursor::new(TEST_STRING));
+    let root = Element::from_reader(&mut reader).unwrap();
+    assert_eq!("en", root.attr("xml:lang").unwrap());
+    assert_eq!("fr", root.get_child("child", "child_ns").unwrap().attr("xml:lang").unwrap());
+}