diff --git a/src/dom.rs b/src/dom.rs index 947f460..4991720 100644 --- a/src/dom.rs +++ b/src/dom.rs @@ -246,6 +246,16 @@ impl<'d> Element<'d> { self.document.storage.element_register_prefix(self.node, prefix, namespace_uri); } + /// Unregister a prefix on this element. This does not check for prefix + /// registrations on any ancestor elements. + /// + /// If the prefix does not exist, returns `None`. Otherwise, returns the + /// `Namespace` that was removed. + pub fn unregister_prefix(&self, prefix: &str) -> Option> { + self.document.storage.element_unregister_prefix(self.node, prefix) + .map(|(prefix, uri)| Namespace { prefix, uri }) + } + /// Recursively resolve the prefix to a namespace URI. pub fn namespace_uri_for_prefix(&self, prefix: &str) -> Option<&'d str> { self.document.connections.element_namespace_uri_for_prefix(self.node, prefix) @@ -262,6 +272,13 @@ impl<'d> Element<'d> { ) } + /// View all the namespaces that are registered on this element, without + /// walking up the tree. + pub fn registered_namespaces(&self) -> impl Iterator> { + self.document.connections.element_registered_namespaces(self.node) + .map(|(prefix, uri)| Namespace { prefix, uri }) + } + /// Retrieve all namespaces that are in scope, recursively walking /// up the document tree. pub fn namespaces_in_scope(&self) -> Vec> { @@ -665,7 +682,7 @@ impl<'d> From> for ChildOfElement<'d> { #[cfg(test)] mod test { use super::super::{Package,QName}; - use super::{ChildOfRoot,ChildOfElement,ParentOfChild}; + use super::{ChildOfRoot,ChildOfElement,ParentOfChild,Namespace}; macro_rules! assert_qname_eq( ($l:expr, $r:expr) => (assert_eq!(Into::::into($l), $r.into())); @@ -1061,6 +1078,82 @@ mod test { assert_eq!("uri2", ns.uri()); } + #[test] + fn elements_get_multiple_registered_namespaces() { + let package = Package::new(); + let doc = package.as_document(); + + let element = doc.create_element("alpha"); + element.register_prefix("a", "uria"); + element.register_prefix("b", "urib"); + element.register_prefix("c", "uric"); + + let nses: Vec = element.registered_namespaces().collect(); + assert_eq!(3, nses.len()); + + let a_ns = nses.iter().find(|ns| ns.prefix() == "a").unwrap(); + assert_eq!("uria", a_ns.uri()); + + let b_ns = nses.iter().find(|ns| ns.prefix() == "b").unwrap(); + assert_eq!("urib", b_ns.uri()); + + let b_ns = nses.iter().find(|ns| ns.prefix() == "b").unwrap(); + assert_eq!("urib", b_ns.uri()); + } + + #[test] + fn elements_get_only_own_registered_namespace() { + let package = Package::new(); + let doc = package.as_document(); + + let parent = doc.create_element("parent"); + parent.register_prefix("parentprefix", "uri1"); + + let child = doc.create_element("child"); + child.register_prefix("ownprefix", "uri2"); + + parent.append_child(child); + + let nses: Vec = child.registered_namespaces().collect(); + assert_eq!(1, nses.len()); + + let ns = nses.iter().find(|ns| ns.prefix() == "ownprefix").unwrap(); + assert_eq!("uri2", ns.uri()); + } + + #[test] + fn elements_unregister_prefixes() { + let package = Package::new(); + let doc = package.as_document(); + + let el = doc.create_element("alpha"); + el.register_prefix("a", "uri_a"); + el.register_prefix("b", "uri_b"); + el.register_prefix("c", "uri_c"); + + assert!(el.registered_namespaces().find(|ns| ns.prefix == "a").is_some()); + assert!(el.registered_namespaces().find(|ns| ns.prefix == "b").is_some()); + assert!(el.registered_namespaces().find(|ns| ns.prefix == "c").is_some()); + + el.unregister_prefix("a"); + + assert!(el.registered_namespaces().find(|ns| ns.prefix == "a").is_none()); + assert!(el.registered_namespaces().find(|ns| ns.prefix == "b").is_some()); + assert!(el.registered_namespaces().find(|ns| ns.prefix == "c").is_some()); + + el.unregister_prefix("c"); + + assert!(el.registered_namespaces().find(|ns| ns.prefix == "a").is_none()); + assert!(el.registered_namespaces().find(|ns| ns.prefix == "b").is_some()); + assert!(el.registered_namespaces().find(|ns| ns.prefix == "c").is_none()); + + el.unregister_prefix("b"); + + assert!(el.registered_namespaces().find(|ns| ns.prefix == "a").is_none()); + assert!(el.registered_namespaces().find(|ns| ns.prefix == "b").is_none()); + assert!(el.registered_namespaces().find(|ns| ns.prefix == "c").is_none()); + } + #[test] fn attributes_belong_to_a_document() { let package = Package::new(); diff --git a/src/lazy_hash_map.rs b/src/lazy_hash_map.rs index 0183624..5b752ac 100644 --- a/src/lazy_hash_map.rs +++ b/src/lazy_hash_map.rs @@ -39,6 +39,13 @@ impl LazyHashMap }) } + pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> + where K: Borrow, + Q: Hash + Eq + { + self.map.as_mut().and_then(|m| m.remove_entry(key)) + } + pub fn iter(&self) -> Iter { Iter(self.map.as_ref().map(|m| m.iter())) } diff --git a/src/raw.rs b/src/raw.rs index 219bd01..bbdb747 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -381,6 +381,11 @@ impl Storage { element_r.prefix_to_namespace.insert(prefix, namespace_uri); } + pub fn element_unregister_prefix(&self, element: *mut Element, prefix: &str) -> Option<(&str, &str)> { + let element_r = unsafe { &mut * element }; + element_r.prefix_to_namespace.remove_entry(prefix).map(|(p, u)| (p.as_slice(), u.as_slice())) + } + pub fn element_set_default_namespace_uri(&self, element: *mut Element, namespace_uri: Option<&str>) { let namespace_uri = namespace_uri.map(|p| self.intern(p)); let element_r = unsafe { &mut * element }; @@ -771,6 +776,14 @@ impl Connections { None } + pub fn element_registered_namespaces(&self, element: *mut Element) + -> impl Iterator + { + let element_ref = unsafe { &*element }; + + element_ref.prefix_to_namespace.iter().map(|(p, n)| (p.as_slice(), n.as_slice())) + } + pub fn element_namespaces_in_scope(&self, element: *mut Element) -> NamespacesInScope {