xml_no_std/
namespace.rs

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