use {XmlReader, Event};
use error::ResultPos;
use std::io::BufRead;
#[derive(Clone)]
struct Namespace {
prefix: Vec<u8>,
value: Vec<u8>,
element_name: Vec<u8>,
level: usize,
}
impl Namespace {
fn is_match(&self, name: &[u8]) -> bool {
let len = self.prefix.len();
name.len() > len && name[len] == b':' && &name[..len] == &*self.prefix
}
}
#[derive(Clone)]
pub struct XmlnsReader<R: BufRead> {
reader: XmlReader<R>,
namespaces: Vec<Namespace>,
}
impl<R: BufRead> XmlnsReader<R> {
pub fn new(reader: XmlReader<R>) -> XmlnsReader<R> {
XmlnsReader {
reader: reader,
namespaces: Vec::new(),
}
}
pub fn resolve<'a, 'b>(&'a self, qname: &'b [u8])
-> (Option<&'a [u8]>, &'b [u8])
{
match self.namespaces.iter().rev().find(|ref n| n.is_match(qname)) {
Some(n) => (Some(&n.value), &qname[(n.prefix.len() + 1)..]),
None => (None, qname),
}
}
}
impl<R: BufRead> Iterator for XmlnsReader<R> {
type Item = ResultPos<(Option<Vec<u8>>, Event)>;
fn next(&mut self) -> Option<Self::Item> {
match self.reader.next() {
Some(Ok(Event::Start(e))) => {
{
let name = e.name();
for n in &mut self.namespaces {
if name == &*n.element_name {
n.level += 1;
}
}
}
for a in e.attributes().with_checks(false) {
if let Ok((k, v)) = a {
if k.len() > 6 && &k[..6] == b"xmlns:" {
self.namespaces.push(Namespace {
prefix: k[6..].to_vec(),
value: v.to_vec(),
element_name: e.name().to_vec(),
level: 1,
});
}
} else {
break;
}
}
let namespace = self.namespaces
.iter()
.rev()
.find(|ref n| n.is_match(e.name()))
.map(|ref n| n.value.clone());
Some(Ok((namespace, Event::Start(e))))
}
Some(Ok(Event::End(e))) => {
{
let name = e.name();
for n in &mut self.namespaces {
if name == &*n.element_name {
n.level -= 1;
}
}
}
match self.namespaces.iter().rev().position(|n| n.level > 0) {
Some(0) | None => (),
Some(p) => {
let len = self.namespaces.len() - p;
self.namespaces.truncate(len)
}
}
let namespace = {
let name = e.name();
self.namespaces
.iter()
.rev()
.find(|ref n| n.is_match(name))
.map(|ref n| n.value.clone())
};
Some(Ok((namespace, Event::End(e))))
}
Some(Ok(e)) => Some(Ok((None, e))),
Some(Err(e)) => Some(Err(e)),
None => None,
}
}
}