xml/
namespace.rs

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