use {XmlReader, Event, Element};
use error::ResultPos;
use std::io::BufRead;
#[derive(Clone)]
struct Namespace {
prefix: Option<Vec<u8>>,
value: Option<Vec<u8>>,
level: i32,
}
impl Namespace {
#[inline]
fn matches_qualified(&self, name: &[u8]) -> bool {
if let Some(ref prefix) = self.prefix {
let len = prefix.len();
name.len() > len && name[len] == b':' && &name[..len] == &prefix[..]
} else {
false
}
}
#[inline]
fn matches_unqualified_elem(&self) -> bool {
self.prefix.is_none()
}
}
#[derive(Clone)]
pub struct XmlnsReader<R: BufRead> {
reader: XmlReader<R>,
namespaces: Vec<Namespace>,
nesting_level: i32,
pending_pop: bool
}
impl<R: BufRead> XmlnsReader<R> {
pub fn new(reader: XmlReader<R>) -> XmlnsReader<R> {
XmlnsReader {
reader: reader,
namespaces: Vec::new(),
nesting_level: 0,
pending_pop: false
}
}
pub fn resolve<'a, 'b>(&'a self, qname: &'b [u8])
-> (Option<&'a [u8]>, &'b [u8])
{
if !qname.contains(&b':') {
return (None, qname)
}
match self.namespaces.iter().rev().find(|ref n| n.matches_qualified(qname)) {
Some(&Namespace { ref prefix, value: Some(ref value), .. }) =>
(Some(&value[..]), &qname[(prefix.as_ref().unwrap().len() + 1)..]),
Some(&Namespace { ref prefix, value: None, .. }) =>
(None, &qname[(prefix.as_ref().unwrap().len() + 1)..]),
None => (None, qname),
}
}
fn find_namespace_value(&self, e: &Element) -> Option<Vec<u8>> {
let element_name = e.name();
if element_name.contains(&b':') {
self.namespaces
.iter()
.rev() .find(|ref n| n.matches_qualified(element_name))
.and_then(|ref n| n.value.as_ref().map(|ns| ns.clone()))
} else {
self.namespaces
.iter()
.rev() .find(|ref n| n.matches_unqualified_elem())
.and_then(|ref n| n.value.as_ref().map(|ns| ns.clone()))
}
}
fn pop_empty_namespaces(&mut self) {
let current_level = self.nesting_level;
match self.namespaces.iter().rposition(|n| n.level <= current_level) {
None => self.namespaces.clear(),
Some(last_valid_pos) => self.namespaces.truncate(last_valid_pos + 1)
}
}
fn push_new_namespaces(&mut self, e: &Element) {
for a in e.attributes().with_checks(false) {
if let Ok((k, v)) = a {
if k.len() >= 5 && &k[..5] == b"xmlns" && (k.len() == 5 || k[5] == b':') {
let prefix = if k.len() == 5 { None } else { Some(k[6..].to_vec()) };
let ns_value = if v.len() == 0 { None } else { Some(v.to_vec()) };
self.namespaces.push(Namespace {
prefix: prefix,
value: ns_value,
level: self.nesting_level,
});
}
} else {
break;
}
}
}
}
impl<R: BufRead> Iterator for XmlnsReader<R> {
type Item = ResultPos<(Option<Vec<u8>>, Event)>;
fn next(&mut self) -> Option<Self::Item> {
if self.pending_pop {
self.pending_pop = false;
self.nesting_level -= 1;
self.pop_empty_namespaces();
}
match self.reader.next() {
Some(Ok(Event::Start(e))) => {
self.nesting_level += 1;
self.push_new_namespaces(&e);
Some(Ok((self.find_namespace_value(&e), Event::Start(e))))
}
Some(Ok(Event::Empty(e))) => {
self.nesting_level += 1;
self.push_new_namespaces(&e);
self.pending_pop = true;
Some(Ok((self.find_namespace_value(&e), Event::Empty(e))))
}
Some(Ok(Event::End(e))) => {
let element_ns = self.find_namespace_value(&e);
self.nesting_level -= 1;
self.pop_empty_namespaces();
Some(Ok((element_ns, Event::End(e))))
}
Some(Ok(e)) => Some(Ok((None, e))),
Some(Err(e)) => Some(Err(e)),
None => None,
}
}
}