1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Module for managing `XmlnsReader` iterator

use {XmlReader, Event, Element};
use error::ResultPos;
use std::io::BufRead;

#[derive(Clone)]
struct Namespace {
    prefix: Vec<u8>,
    value: Vec<u8>,
    element_name: Vec<u8>,
    level: i32,
}

impl Namespace {
    fn is_match(&self, name: &[u8]) -> bool {
        let len = self.prefix.len();
        name.len() > len && name[len] == b':' && &name[..len] == &*self.prefix
    }
}

/// `XmlnsReader` iterator which wraps `XmlReader` iterator and
/// adds namespace resolutions
///
/// # Example
///
/// ```
/// use quick_xml::{XmlReader, Event};
/// use quick_xml::namespace::XmlnsReader;
///
/// let xml = r#"<tag1 att1 = "test">
///                 <tag2><!--Test comment-->Test</tag2>
///                 <tag2>Test 2</tag2>
///             </tag1>"#;
/// let mut reader = XmlReader::from(xml).trim_text(true)
///                  .namespaced();
/// let mut count = 0;
/// let mut txt = Vec::new();
/// // need to use `while let` in order to have access to `reader.resolve` 
/// // for attributes namespaces
/// while let Some(r) = reader.next() {
///     match r {
///         // XmlnsReader iterates ResultPos<(Option<&[u8]>, Event)> with 
///         // the Option<&[u8]> being the resolved Namespace, if any
///         Ok((ref n, Event::Start(ref e))) => {
///             match e.name() {
///                 b"tag1" => println!("attributes keys: {:?}",
///                                  e.attributes()
///                                  // use `reader.resolve` to get attribute
///                                  // namespace resolution
///                                  .map(|a| reader.resolve(a.unwrap().0))
///                                  .collect::<Vec<_>>()),
///                 b"tag2" => count += 1,
///                 _ => (),
///             }
///         },
///         Ok((_, Event::Text(e))) => txt.push(e.into_string()),
///         Err((e, pos)) => panic!("{:?} at position {}", e, pos),
///         _ => (),
///     }
/// }
/// ```
#[derive(Clone)]
pub struct XmlnsReader<R: BufRead> {
    reader: XmlReader<R>,
    namespaces: Vec<Namespace>,
}

impl<R: BufRead> XmlnsReader<R> {
    /// Converts a `XmlReader` into a `XmlnsReader` iterator
    pub fn new(reader: XmlReader<R>) -> XmlnsReader<R> {
        XmlnsReader {
            reader: reader,
            namespaces: Vec::new(),
        }
    }

    /// Resolves a qualified name into (namespace value, local name)
    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),
        }
    }

    fn find_namespace_value(&self, e: &Element) -> Option<Vec<u8>> {
        self.namespaces
            .iter()
            .rev() // iterate in reverse order to find the most recent one
            .find(|ref n| n.is_match(e.name()))
            .map(|ref n| n.value.clone())
    }

    fn pop_empty_namespaces(&mut self) {
        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)
            }
        }
    }

    fn push_new_namespaces(&mut self, e: &Element) {
        // adds new namespaces for attributes starting with 'xmlns:'
        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;
            }
        }
    }

    fn update_existing_ns_level(&mut self, e: &Element, increment: i32) {
        let name = e.name();
        for n in &mut self.namespaces {
            if name == &*n.element_name {
                n.level += increment;
            }
        }
    }
}

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))) => {
                self.update_existing_ns_level(&e, 1);
                self.push_new_namespaces(&e);
                Some(Ok((self.find_namespace_value(&e), Event::Start(e))))
            }
            Some(Ok(Event::Empty(e))) => {
                Some(Ok((self.find_namespace_value(&e), Event::Empty(e))))
            }
            Some(Ok(Event::End(e))) => {
                self.update_existing_ns_level(&e, -1);
                self.pop_empty_namespaces();
                Some(Ok((self.find_namespace_value(&e), Event::End(e))))
            }
            Some(Ok(e)) => Some(Ok((None, e))),
            Some(Err(e)) => Some(Err(e)),
            None => None,
        }
    }
}