Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an API to get and remove prefixes registered directly on an element #73

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 94 additions & 1 deletion src/dom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Namespace<'d>> {
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)
Expand All @@ -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<Item=Namespace<'d>> {
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<Namespace<'d>> {
Expand Down Expand Up @@ -665,7 +682,7 @@ impl<'d> From<ChildOfRoot<'d>> 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::<QName>::into($l), $r.into()));
Expand Down Expand Up @@ -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<Namespace> = 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<Namespace> = 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();
Expand Down
7 changes: 7 additions & 0 deletions src/lazy_hash_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ impl<K, V> LazyHashMap<K, V>
})
}

pub fn remove_entry<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
where K: Borrow<Q>,
Q: Hash + Eq
{
self.map.as_mut().and_then(|m| m.remove_entry(key))
}

pub fn iter(&self) -> Iter<K, V> {
Iter(self.map.as_ref().map(|m| m.iter()))
}
Expand Down
13 changes: 13 additions & 0 deletions src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -771,6 +776,14 @@ impl Connections {
None
}

pub fn element_registered_namespaces(&self, element: *mut Element)
-> impl Iterator<Item=(&str, &str)>
{
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
{
Expand Down