xml/
namespace.rs

1//! Contains namespace manipulation types and functions.
2
3use std::iter::{Map, Rev};
4use std::collections::btree_map::{BTreeMap, Entry};
5use std::collections::btree_map::Iter as Entries;
6use std::collections::HashSet;
7use std::slice::Iter;
8
9/// Designates prefix for namespace definitions.
10///
11/// See [Namespaces in XML][namespace] spec for more information.
12///
13///   [namespace]: http://www.w3.org/TR/xml-names/#ns-decl
14pub const NS_XMLNS_PREFIX: &'static str = "xmlns";
15
16/// Designates the standard URI for `xmlns` prefix.
17///
18/// See [A Namespace Name for xmlns Attributes][1] for more information.
19///
20///   [namespace]: http://www.w3.org/2000/xmlns/
21pub const NS_XMLNS_URI: &'static str    = "http://www.w3.org/2000/xmlns/";
22
23/// Designates prefix for a namespace containing several special predefined attributes.
24///
25/// See [2.10 White Space handling][1],  [2.1 Language Identification][2],
26/// [XML Base specification][3] and [xml:id specification][4] for more information.
27///
28///   [1]: http://www.w3.org/TR/REC-xml/#sec-white-space
29///   [2]: http://www.w3.org/TR/REC-xml/#sec-lang-tag
30///   [3]: http://www.w3.org/TR/xmlbase/
31///   [4]: http://www.w3.org/TR/xml-id/
32pub const NS_XML_PREFIX: &'static str   = "xml";
33
34/// Designates the standard URI for `xml` prefix.
35///
36/// See `NS_XML_PREFIX` documentation for more information.
37pub const NS_XML_URI: &'static str      = "http://www.w3.org/XML/1998/namespace";
38
39/// Designates the absence of prefix in a qualified name.
40///
41/// This constant should be used to define or query default namespace which should be used
42/// for element or attribute names without prefix. For example, if a namespace mapping
43/// at a particular point in the document contains correspondence like
44///
45/// ```none
46///   NS_NO_PREFIX  -->  urn:some:namespace
47/// ```
48///
49/// then all names declared without an explicit prefix `urn:some:namespace` is assumed as
50/// a namespace URI.
51///
52/// By default empty prefix corresponds to absence of namespace, but this can change either
53/// when writing an XML document (manually) or when reading an XML document (based on namespace
54/// declarations).
55pub const NS_NO_PREFIX: &'static str    = "";
56
57/// Designates an empty namespace URI, which is equivalent to absence of namespace.
58///
59/// This constant should not usually be used directly; it is used to designate that
60/// empty prefix corresponds to absent namespace in `NamespaceStack` instances created with
61/// `NamespaceStack::default()`. Therefore, it can be used to restore `NS_NO_PREFIX` mapping
62/// in a namespace back to its default value.
63pub const NS_EMPTY_URI: &'static str    = "";
64
65/// Namespace is a map from prefixes to namespace URIs.
66///
67/// No prefix (i.e. default namespace) is designated by `NS_NO_PREFIX` constant.
68#[derive(PartialEq, Eq, Clone, Debug)]
69pub struct Namespace(pub BTreeMap<String, String>);
70
71impl Namespace {
72    /// Returns an empty namespace.
73    #[inline]
74    pub fn empty() -> Namespace { Namespace(BTreeMap::new()) }
75
76    /// Checks whether this namespace is empty.
77    #[inline]
78    pub fn is_empty(&self) -> bool {
79        self.0.is_empty()
80    }
81
82    /// Checks whether this namespace is essentially empty, that is, it does not contain
83    /// anything but default mappings.
84    pub fn is_essentially_empty(&self) -> bool {
85        // a shortcut for a namespace which is definitely not empty
86        if self.0.len() > 3 { return false; }
87
88        self.0.iter().all(|(k, v)| match (&**k, &**v) {
89            (NS_NO_PREFIX,    NS_EMPTY_URI) => true,
90            (NS_XMLNS_PREFIX, NS_XMLNS_URI) => true,
91            (NS_XML_PREFIX,   NS_XML_URI)   => true,
92            _ => false
93        })
94    }
95
96    /// Checks whether this namespace mapping contains the given prefix.
97    ///
98    /// # Parameters
99    /// * `prefix`  --- namespace prefix.
100    ///
101    /// # Return value
102    /// `true` if this namespace contains the given prefix, `false` otherwise.
103    #[inline]
104    pub fn contains<P: ?Sized+AsRef<str>>(&self, prefix: &P) -> bool {
105        self.0.contains_key(prefix.as_ref())
106    }
107
108    /// Puts a mapping into this namespace.
109    ///
110    /// This method does not override any already existing mappings.
111    ///
112    /// Returns a boolean flag indicating whether the map already contained
113    /// the given prefix.
114    ///
115    /// # Parameters
116    /// * `prefix` --- namespace prefix;
117    /// * `uri`    --- namespace URI.
118    ///
119    /// # Return value
120    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
121    /// was already present in the namespace.
122    pub fn put<P, U>(&mut self, prefix: P, uri: U) -> bool
123        where P: Into<String>, U: Into<String>
124    {
125        match self.0.entry(prefix.into()) {
126            Entry::Occupied(_) => false,
127            Entry::Vacant(ve) => {
128                ve.insert(uri.into());
129                true
130            }
131        }
132    }
133
134    /// Puts a mapping into this namespace forcefully.
135    ///
136    /// This method, unlike `put()`, does replace an already existing mapping.
137    ///
138    /// Returns previous URI which was assigned to the given prefix, if it is present.
139    ///
140    /// # Parameters
141    /// * `prefix` --- namespace prefix;
142    /// * `uri`    --- namespace URI.
143    ///
144    /// # Return value
145    /// `Some(uri)` with `uri` being a previous URI assigned to the `prefix`, or
146    /// `None` if such prefix was not present in the namespace before.
147    pub fn force_put<P, U>(&mut self, prefix: P, uri: U) -> Option<String>
148        where P: Into<String>, U: Into<String>
149    {
150        self.0.insert(prefix.into(), uri.into())
151    }
152
153    /// Queries the namespace for the given prefix.
154    ///
155    /// # Parameters
156    /// * `prefix` --- namespace prefix.
157    ///
158    /// # Return value
159    /// Namespace URI corresponding to the given prefix, if it is present.
160    pub fn get<'a, P: ?Sized+AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str> {
161        self.0.get(prefix.as_ref()).map(|s| &**s)
162    }
163}
164
165/// An alias for iterator type for namespace mappings contained in a namespace.
166pub type NamespaceMappings<'a> = Map<
167    Entries<'a, String, String>,
168    for<'b> fn((&'b String, &'b String)) -> UriMapping<'b>
169>;
170
171impl<'a> IntoIterator for &'a Namespace {
172    type Item = UriMapping<'a>;
173    type IntoIter = NamespaceMappings<'a>;
174
175    fn into_iter(self) -> Self::IntoIter {
176        fn mapper<'a>((prefix, uri): (&'a String, &'a String)) -> UriMapping<'a> {
177            (&*prefix, &*uri)
178        }
179        self.0.iter().map(mapper)
180    }
181}
182
183/// Namespace stack is a sequence of namespaces.
184///
185/// Namespace stack is used to represent cumulative namespace consisting of
186/// combined namespaces from nested elements.
187#[derive(Clone, Eq, PartialEq, Debug)]
188pub struct NamespaceStack(pub Vec<Namespace>);
189
190impl NamespaceStack {
191    /// Returns an empty namespace stack.
192    #[inline]
193    pub fn empty() -> NamespaceStack { NamespaceStack(Vec::with_capacity(2)) }
194
195    /// Returns a namespace stack with default items in it.
196    ///
197    /// Default items are the following:
198    ///
199    /// * `xml` → `http://www.w3.org/XML/1998/namespace`;
200    /// * `xmlns` → `http://www.w3.org/2000/xmlns/`.
201    #[inline]
202    pub fn default() -> NamespaceStack {
203        let mut nst = NamespaceStack::empty();
204        nst.push_empty();
205        // xml namespace
206        nst.put(NS_XML_PREFIX, NS_XML_URI);
207        // xmlns namespace
208        nst.put(NS_XMLNS_PREFIX, NS_XMLNS_URI);
209        // empty namespace
210        nst.put(NS_NO_PREFIX, NS_EMPTY_URI);
211        nst
212    }
213
214    /// Adds an empty namespace to the top of this stack.
215    #[inline]
216    pub fn push_empty(&mut self) -> &mut NamespaceStack {
217        self.0.push(Namespace::empty());
218        self
219    }
220
221    /// Removes the topmost namespace in this stack.
222    ///
223    /// Panics if the stack is empty.
224    #[inline]
225    pub fn pop(&mut self) -> Namespace {
226        self.0.pop().unwrap()
227    }
228
229    /// Removes the topmost namespace in this stack.
230    ///
231    /// Returns `Some(namespace)` if this stack is not empty and `None` otherwise.
232    #[inline]
233    pub fn try_pop(&mut self) -> Option<Namespace> {
234        self.0.pop()
235    }
236
237    /// Borrows the topmost namespace mutably, leaving the stack intact.
238    ///
239    /// Panics if the stack is empty.
240    #[inline]
241    pub fn peek_mut(&mut self) -> &mut Namespace {
242        self.0.last_mut().unwrap()
243    }
244
245    /// Borrows the topmost namespace immutably, leaving the stack intact.
246    ///
247    /// Panics if the stack is empty.
248    #[inline]
249    pub fn peek(&self) -> &Namespace {
250        self.0.last().unwrap()
251    }
252
253    /// Puts a mapping into the topmost namespace if this stack does not already contain one.
254    ///
255    /// Returns a boolean flag indicating whether the insertion has completed successfully.
256    /// Note that both key and value are matched and the mapping is inserted if either
257    /// namespace prefix is not already mapped, or if it is mapped, but to a different URI.
258    ///
259    /// # Parameters
260    /// * `prefix` --- namespace prefix;
261    /// * `uri`    --- namespace URI.
262    ///
263    /// # Return value
264    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
265    /// was already present in the namespace stack.
266    pub fn put_checked<P, U>(&mut self, prefix: P, uri: U) -> bool
267        where P: Into<String> + AsRef<str>,
268              U: Into<String> + AsRef<str>
269    {
270        if self.0.iter().any(|ns| ns.get(&prefix) == Some(uri.as_ref())) {
271            false
272        } else {
273            self.put(prefix, uri);
274            true
275        }
276    }
277
278    /// Puts a mapping into the topmost namespace in this stack.
279    ///
280    /// This method does not override a mapping in the topmost namespace if it is
281    /// already present, however, it does not depend on other namespaces in the stack,
282    /// so it is possible to put a mapping which is present in lower namespaces.
283    ///
284    /// Returns a boolean flag indicating whether the insertion has completed successfully.
285    ///
286    /// # Parameters
287    /// * `prefix` --- namespace prefix;
288    /// * `uri`    --- namespace URI.
289    ///
290    /// # Return value
291    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
292    /// was already present in the namespace.
293    #[inline]
294    pub fn put<P, U>(&mut self, prefix: P, uri: U) -> bool
295        where P: Into<String>, U: Into<String>
296    {
297        self.0.last_mut().unwrap().put(prefix, uri)
298    }
299
300    /// Performs a search for the given prefix in the whole stack.
301    ///
302    /// This method walks the stack from top to bottom, querying each namespace
303    /// in order for the given prefix. If none of the namespaces contains the prefix,
304    /// `None` is returned.
305    ///
306    /// # Parameters
307    /// * `prefix` --- namespace prefix.
308    #[inline]
309    pub fn get<'a, P: ?Sized+AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str> {
310        let prefix = prefix.as_ref();
311        for ns in self.0.iter().rev() {
312            match ns.get(prefix) {
313                None => {},
314                r => return r,
315            }
316        }
317        None
318    }
319
320    /// Combines this stack of namespaces into a single namespace.
321    ///
322    /// Namespaces are combined in left-to-right order, that is, rightmost namespace
323    /// elements take priority over leftmost ones.
324    pub fn squash(&self) -> Namespace {
325        let mut result = BTreeMap::new();
326        for ns in self.0.iter() {
327            result.extend(ns.0.iter().map(|(k, v)| (k.clone(), v.clone())));
328        }
329        Namespace(result)
330    }
331
332    /// Returns an object which implements `Extend` using `put_checked()` instead of `put()`.
333    ///
334    /// See `CheckedTarget` for more information.
335    #[inline]
336    pub fn checked_target(&mut self) -> CheckedTarget {
337        CheckedTarget(self)
338    }
339
340    /// Returns an iterator over all mappings in this namespace stack.
341    #[inline]
342    pub fn iter(&self) -> NamespaceStackMappings {
343        self.into_iter()
344    }
345}
346
347/// An iterator over mappings from prefixes to URIs in a namespace stack.
348///
349/// # Example
350/// ```
351/// # use xml::namespace::NamespaceStack;
352/// let mut nst = NamespaceStack::empty();
353/// nst.push_empty();
354/// nst.put("a", "urn:A");
355/// nst.put("b", "urn:B");
356/// nst.push_empty();
357/// nst.put("c", "urn:C");
358///
359/// assert_eq!(vec![("c", "urn:C"), ("a", "urn:A"), ("b", "urn:B")], nst.iter().collect::<Vec<_>>());
360/// ```
361pub struct NamespaceStackMappings<'a> {
362    namespaces: Rev<Iter<'a, Namespace>>,
363    current_namespace: Option<NamespaceMappings<'a>>,
364    used_keys: HashSet<&'a str>
365}
366
367impl<'a> NamespaceStackMappings<'a> {
368    fn go_to_next_namespace(&mut self) -> bool {
369        self.current_namespace = self.namespaces.next().map(|ns| ns.into_iter());
370        self.current_namespace.is_some()
371    }
372}
373
374impl<'a> Iterator for NamespaceStackMappings<'a> {
375    type Item = UriMapping<'a>;
376
377    fn next(&mut self) -> Option<UriMapping<'a>> {
378        // If there is no current namespace and no next namespace, we're finished
379        if self.current_namespace.is_none() && !self.go_to_next_namespace() {
380            return None;
381        }
382        let next_item = self.current_namespace.as_mut().unwrap().next();
383
384        match next_item {
385            // There is an element in the current namespace
386            Some((k, v)) => if self.used_keys.contains(&k) {
387                // If the current key is used, go to the next one
388                self.next()
389            } else {
390                // Otherwise insert the current key to the set of used keys and
391                // return the mapping
392                self.used_keys.insert(k);
393                Some((k, v))
394            },
395            // Current namespace is exhausted
396            None => if self.go_to_next_namespace() {
397                // If there is next namespace, continue from it
398                self.next()
399            } else {
400                // No next namespace, exiting
401                None
402            }
403        }
404    }
405}
406
407impl<'a> IntoIterator for &'a NamespaceStack {
408    type Item = UriMapping<'a>;
409    type IntoIter = NamespaceStackMappings<'a>;
410
411    fn into_iter(self) -> Self::IntoIter {
412        NamespaceStackMappings {
413            namespaces: self.0.iter().rev(),
414            current_namespace: None,
415            used_keys: HashSet::new()
416        }
417    }
418}
419
420/// A type alias for a pair of `(prefix, uri)` values returned by namespace iterators.
421pub type UriMapping<'a> = (&'a str, &'a str);
422
423impl<'a> Extend<UriMapping<'a>> for Namespace {
424    fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>> {
425        for (prefix, uri) in iterable {
426            self.put(prefix, uri);
427        }
428    }
429}
430
431impl<'a> Extend<UriMapping<'a>> for NamespaceStack {
432    fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>> {
433        for (prefix, uri) in iterable {
434            self.put(prefix, uri);
435        }
436    }
437}
438
439/// A wrapper around `NamespaceStack` which implements `Extend` using `put_checked()`.
440///
441/// # Example
442///
443/// ```
444/// # use xml::namespace::NamespaceStack;
445///
446/// let mut nst = NamespaceStack::empty();
447/// nst.push_empty();
448/// nst.put("a", "urn:A");
449/// nst.put("b", "urn:B");
450/// nst.push_empty();
451/// nst.put("c", "urn:C");
452///
453/// nst.checked_target().extend(vec![("a", "urn:Z"), ("b", "urn:B"), ("c", "urn:Y"), ("d", "urn:D")]);
454/// assert_eq!(
455///     vec![("a", "urn:Z"), ("c", "urn:C"), ("d", "urn:D"), ("b", "urn:B")],
456///     nst.iter().collect::<Vec<_>>()
457/// );
458/// ```
459///
460/// Compare:
461///
462/// ```
463/// # use xml::namespace::NamespaceStack;
464/// # let mut nst = NamespaceStack::empty();
465/// # nst.push_empty();
466/// # nst.put("a", "urn:A");
467/// # nst.put("b", "urn:B");
468/// # nst.push_empty();
469/// # nst.put("c", "urn:C");
470///
471/// nst.extend(vec![("a", "urn:Z"), ("b", "urn:B"), ("c", "urn:Y"), ("d", "urn:D")]);
472/// assert_eq!(
473///     vec![("a", "urn:Z"), ("b", "urn:B"), ("c", "urn:C"), ("d", "urn:D")],
474///     nst.iter().collect::<Vec<_>>()
475/// );
476/// ```
477pub struct CheckedTarget<'a>(&'a mut NamespaceStack);
478
479impl<'a, 'b> Extend<UriMapping<'b>> for CheckedTarget<'a> {
480    fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'b>> {
481        for (prefix, uri) in iterable {
482            self.0.put_checked(prefix, uri);
483        }
484    }
485}