1 //! Contains namespace manipulation types and functions.
2 
3 use std::borrow::Cow;
4 use std::collections::btree_map::Iter as Entries;
5 use std::collections::btree_map::{BTreeMap, Entry};
6 use std::collections::HashSet;
7 use std::iter::{Map, Rev};
8 use 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
15 pub 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/
22 pub 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/
33 pub 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.
38 pub 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).
56 pub 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.
64 pub 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)]
70 pub struct Namespace(pub BTreeMap<String, String>);
71 
72 impl Namespace {
73     /// Returns an empty namespace.
74     #[inline]
75     #[must_use]
empty() -> Namespace76     pub fn empty() -> Namespace {
77         Namespace(BTreeMap::new())
78     }
79 
80     /// Checks whether this namespace is empty.
81     #[inline]
82     #[must_use]
is_empty(&self) -> bool83     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]
is_essentially_empty(&self) -> bool90     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)| match (&**k, &**v) {
95             (NS_NO_PREFIX,    NS_EMPTY_URI) => true,
96             (NS_XMLNS_PREFIX, NS_XMLNS_URI) => true,
97             (NS_XML_PREFIX,   NS_XML_URI)   => true,
98             _ => false
99         })
100     }
101 
102     /// Checks whether this namespace mapping contains the given prefix.
103     ///
104     /// # Parameters
105     /// * `prefix`  --- namespace prefix.
106     ///
107     /// # Return value
108     /// `true` if this namespace contains the given prefix, `false` otherwise.
109     #[inline]
contains<P: ?Sized + AsRef<str>>(&self, prefix: &P) -> bool110     pub fn contains<P: ?Sized + AsRef<str>>(&self, prefix: &P) -> bool {
111         self.0.contains_key(prefix.as_ref())
112     }
113 
114     /// Puts a mapping into this namespace.
115     ///
116     /// This method does not override any already existing mappings.
117     ///
118     /// Returns a boolean flag indicating whether the map already contained
119     /// the given prefix.
120     ///
121     /// # Parameters
122     /// * `prefix` --- namespace prefix;
123     /// * `uri`    --- namespace URI.
124     ///
125     /// # Return value
126     /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
127     /// was already present in the namespace.
put<P, U>(&mut self, prefix: P, uri: U) -> bool where P: Into<String>, U: Into<String>128     pub fn put<P, U>(&mut self, prefix: P, uri: U) -> bool
129         where P: Into<String>, U: Into<String>
130     {
131         match self.0.entry(prefix.into()) {
132             Entry::Occupied(_) => false,
133             Entry::Vacant(ve) => {
134                 ve.insert(uri.into());
135                 true
136             }
137         }
138     }
139 
140     /// Puts a mapping into this namespace forcefully.
141     ///
142     /// This method, unlike `put()`, does replace an already existing mapping.
143     ///
144     /// Returns previous URI which was assigned to the given prefix, if it is present.
145     ///
146     /// # Parameters
147     /// * `prefix` --- namespace prefix;
148     /// * `uri`    --- namespace URI.
149     ///
150     /// # Return value
151     /// `Some(uri)` with `uri` being a previous URI assigned to the `prefix`, or
152     /// `None` if such prefix was not present in the namespace before.
force_put<P, U>(&mut self, prefix: P, uri: U) -> Option<String> where P: Into<String>, U: Into<String>153     pub fn force_put<P, U>(&mut self, prefix: P, uri: U) -> Option<String>
154         where P: Into<String>, U: Into<String>
155     {
156         self.0.insert(prefix.into(), uri.into())
157     }
158 
159     /// Queries the namespace for the given prefix.
160     ///
161     /// # Parameters
162     /// * `prefix` --- namespace prefix.
163     ///
164     /// # Return value
165     /// Namespace URI corresponding to the given prefix, if it is present.
get<'a, P: ?Sized + AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str>166     pub fn get<'a, P: ?Sized + AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str> {
167         self.0.get(prefix.as_ref()).map(|s| &**s)
168     }
169 
170     /// Borrowed namespace for the writer
171     #[must_use]
borrow(&self) -> Cow<'_, Self>172     pub fn borrow(&self) -> Cow<'_, Self> {
173         Cow::Borrowed(self)
174     }
175 }
176 
177 /// An alias for iterator type for namespace mappings contained in a namespace.
178 pub type NamespaceMappings<'a> = Map<
179     Entries<'a, String, String>,
180     for<'b> fn((&'b String, &'b String)) -> UriMapping<'b>
181 >;
182 
183 impl<'a> IntoIterator for &'a Namespace {
184     type Item = UriMapping<'a>;
185     type IntoIter = NamespaceMappings<'a>;
186 
into_iter(self) -> Self::IntoIter187     fn into_iter(self) -> Self::IntoIter {
188         fn mapper<'a>((prefix, uri): (&'a String, &'a String)) -> UriMapping<'a> {
189             (prefix, uri)
190         }
191         self.0.iter().map(mapper)
192     }
193 }
194 
195 /// Namespace stack is a sequence of namespaces.
196 ///
197 /// Namespace stack is used to represent cumulative namespace consisting of
198 /// combined namespaces from nested elements.
199 #[derive(Clone, Eq, PartialEq, Debug)]
200 pub struct NamespaceStack(pub Vec<Namespace>);
201 
202 impl NamespaceStack {
203     /// Returns an empty namespace stack.
204     #[inline]
205     #[must_use]
empty() -> NamespaceStack206     pub fn empty() -> NamespaceStack {
207         NamespaceStack(Vec::with_capacity(2))
208     }
209 
210     /// Returns a namespace stack with default items in it.
211     ///
212     /// Default items are the following:
213     ///
214     /// * `xml` → `http://www.w3.org/XML/1998/namespace`;
215     /// * `xmlns` → `http://www.w3.org/2000/xmlns/`.
216     #[inline]
217     #[must_use]
default() -> NamespaceStack218     pub fn default() -> NamespaceStack {
219         let mut nst = NamespaceStack::empty();
220         nst.push_empty();
221         // xml namespace
222         nst.put(NS_XML_PREFIX, NS_XML_URI);
223         // xmlns namespace
224         nst.put(NS_XMLNS_PREFIX, NS_XMLNS_URI);
225         // empty namespace
226         nst.put(NS_NO_PREFIX, NS_EMPTY_URI);
227         nst
228     }
229 
230     /// Adds an empty namespace to the top of this stack.
231     #[inline]
push_empty(&mut self) -> &mut NamespaceStack232     pub fn push_empty(&mut self) -> &mut NamespaceStack {
233         self.0.push(Namespace::empty());
234         self
235     }
236 
237     /// Removes the topmost namespace in this stack.
238     ///
239     /// Panics if the stack is empty.
240     #[inline]
pop(&mut self) -> Namespace241     pub fn pop(&mut self) -> Namespace {
242         self.0.pop().unwrap()
243     }
244 
245     /// Removes the topmost namespace in this stack.
246     ///
247     /// Returns `Some(namespace)` if this stack is not empty and `None` otherwise.
248     #[inline]
try_pop(&mut self) -> Option<Namespace>249     pub fn try_pop(&mut self) -> Option<Namespace> {
250         self.0.pop()
251     }
252 
253     /// Borrows the topmost namespace mutably, leaving the stack intact.
254     ///
255     /// Panics if the stack is empty.
256     #[inline]
peek_mut(&mut self) -> &mut Namespace257     pub fn peek_mut(&mut self) -> &mut Namespace {
258         self.0.last_mut().unwrap()
259     }
260 
261     /// Borrows the topmost namespace immutably, leaving the stack intact.
262     ///
263     /// Panics if the stack is empty.
264     #[inline]
265     #[must_use]
peek(&self) -> &Namespace266     pub fn peek(&self) -> &Namespace {
267         self.0.last().unwrap()
268     }
269 
270     /// Puts a mapping into the topmost namespace if this stack does not already contain one.
271     ///
272     /// Returns a boolean flag indicating whether the insertion has completed successfully.
273     /// Note that both key and value are matched and the mapping is inserted if either
274     /// namespace prefix is not already mapped, or if it is mapped, but to a different URI.
275     ///
276     /// # Parameters
277     /// * `prefix` --- namespace prefix;
278     /// * `uri`    --- namespace URI.
279     ///
280     /// # Return value
281     /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
282     /// was already present in the namespace stack.
put_checked<P, U>(&mut self, prefix: P, uri: U) -> bool where P: Into<String> + AsRef<str>, U: Into<String> + AsRef<str>283     pub fn put_checked<P, U>(&mut self, prefix: P, uri: U) -> bool
284         where P: Into<String> + AsRef<str>,
285               U: Into<String> + AsRef<str>
286     {
287         if self.0.iter().any(|ns| ns.get(&prefix) == Some(uri.as_ref())) {
288             false
289         } else {
290             self.put(prefix, uri);
291             true
292         }
293     }
294 
295     /// Puts a mapping into the topmost namespace in this stack.
296     ///
297     /// This method does not override a mapping in the topmost namespace if it is
298     /// already present, however, it does not depend on other namespaces in the stack,
299     /// so it is possible to put a mapping which is present in lower namespaces.
300     ///
301     /// Returns a boolean flag indicating whether the insertion has completed successfully.
302     ///
303     /// # Parameters
304     /// * `prefix` --- namespace prefix;
305     /// * `uri`    --- namespace URI.
306     ///
307     /// # Return value
308     /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
309     /// was already present in the namespace.
310     #[inline]
put<P, U>(&mut self, prefix: P, uri: U) -> bool where P: Into<String>, U: Into<String>311     pub fn put<P, U>(&mut self, prefix: P, uri: U) -> bool
312         where P: Into<String>, U: Into<String>
313     {
314         if let Some(ns) = self.0.last_mut() {
315             ns.put(prefix, uri)
316         } else {
317             false
318         }
319     }
320 
321     /// Performs a search for the given prefix in the whole stack.
322     ///
323     /// This method walks the stack from top to bottom, querying each namespace
324     /// in order for the given prefix. If none of the namespaces contains the prefix,
325     /// `None` is returned.
326     ///
327     /// # Parameters
328     /// * `prefix` --- namespace prefix.
329     #[inline]
get<'a, P: ?Sized + AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str>330     pub fn get<'a, P: ?Sized + AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str> {
331         let prefix = prefix.as_ref();
332         for ns in self.0.iter().rev() {
333             match ns.get(prefix) {
334                 None => {},
335                 r => return r,
336             }
337         }
338         None
339     }
340 
341     /// Combines this stack of namespaces into a single namespace.
342     ///
343     /// Namespaces are combined in left-to-right order, that is, rightmost namespace
344     /// elements take priority over leftmost ones.
345     #[must_use]
squash(&self) -> Namespace346     pub fn squash(&self) -> Namespace {
347         let mut result = BTreeMap::new();
348         for ns in &self.0 {
349             result.extend(ns.0.iter().map(|(k, v)| (k.clone(), v.clone())));
350         }
351         Namespace(result)
352     }
353 
354     /// Returns an object which implements `Extend` using `put_checked()` instead of `put()`.
355     ///
356     /// See `CheckedTarget` for more information.
357     #[inline]
checked_target(&mut self) -> CheckedTarget<'_>358     pub fn checked_target(&mut self) -> CheckedTarget<'_> {
359         CheckedTarget(self)
360     }
361 
362     /// Returns an iterator over all mappings in this namespace stack.
363     #[inline]
364     #[must_use]
iter(&self) -> NamespaceStackMappings<'_>365     pub fn iter(&self) -> NamespaceStackMappings<'_> {
366         self.into_iter()
367     }
368 }
369 
370 /// An iterator over mappings from prefixes to URIs in a namespace stack.
371 ///
372 /// # Example
373 /// ```
374 /// # use xml::namespace::NamespaceStack;
375 /// let mut nst = NamespaceStack::empty();
376 /// nst.push_empty();
377 /// nst.put("a", "urn:A");
378 /// nst.put("b", "urn:B");
379 /// nst.push_empty();
380 /// nst.put("c", "urn:C");
381 ///
382 /// assert_eq!(vec![("c", "urn:C"), ("a", "urn:A"), ("b", "urn:B")], nst.iter().collect::<Vec<_>>());
383 /// ```
384 pub struct NamespaceStackMappings<'a> {
385     namespaces: Rev<Iter<'a, Namespace>>,
386     current_namespace: Option<NamespaceMappings<'a>>,
387     used_keys: HashSet<&'a str>,
388 }
389 
390 impl<'a> NamespaceStackMappings<'a> {
go_to_next_namespace(&mut self) -> bool391     fn go_to_next_namespace(&mut self) -> bool {
392         self.current_namespace = self.namespaces.next().map(|ns| ns.into_iter());
393         self.current_namespace.is_some()
394     }
395 }
396 
397 impl<'a> Iterator for NamespaceStackMappings<'a> {
398     type Item = UriMapping<'a>;
399 
next(&mut self) -> Option<UriMapping<'a>>400     fn next(&mut self) -> Option<UriMapping<'a>> {
401         // If there is no current namespace and no next namespace, we're finished
402         if self.current_namespace.is_none() && !self.go_to_next_namespace() {
403             return None;
404         }
405         let next_item = self.current_namespace.as_mut()?.next();
406 
407         match next_item {
408             // There is an element in the current namespace
409             Some((k, v)) => if self.used_keys.contains(&k) {
410                 // If the current key is used, go to the next one
411                 self.next()
412             } else {
413                 // Otherwise insert the current key to the set of used keys and
414                 // return the mapping
415                 self.used_keys.insert(k);
416                 Some((k, v))
417             },
418             // Current namespace is exhausted
419             None => if self.go_to_next_namespace() {
420                 // If there is next namespace, continue from it
421                 self.next()
422             } else {
423                 // No next namespace, exiting
424                 None
425             }
426         }
427     }
428 }
429 
430 impl<'a> IntoIterator for &'a NamespaceStack {
431     type Item = UriMapping<'a>;
432     type IntoIter = NamespaceStackMappings<'a>;
433 
into_iter(self) -> Self::IntoIter434     fn into_iter(self) -> Self::IntoIter {
435         NamespaceStackMappings {
436             namespaces: self.0.iter().rev(),
437             current_namespace: None,
438             used_keys: HashSet::new(),
439         }
440     }
441 }
442 
443 /// A type alias for a pair of `(prefix, uri)` values returned by namespace iterators.
444 pub type UriMapping<'a> = (&'a str, &'a str);
445 
446 impl<'a> Extend<UriMapping<'a>> for Namespace {
extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>>447     fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>> {
448         for (prefix, uri) in iterable {
449             self.put(prefix, uri);
450         }
451     }
452 }
453 
454 impl<'a> Extend<UriMapping<'a>> for NamespaceStack {
extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>>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 
462 /// A wrapper around `NamespaceStack` which implements `Extend` using `put_checked()`.
463 ///
464 /// # Example
465 ///
466 /// ```
467 /// # use xml::namespace::NamespaceStack;
468 ///
469 /// let mut nst = NamespaceStack::empty();
470 /// nst.push_empty();
471 /// nst.put("a", "urn:A");
472 /// nst.put("b", "urn:B");
473 /// nst.push_empty();
474 /// nst.put("c", "urn:C");
475 ///
476 /// nst.checked_target().extend(vec![("a", "urn:Z"), ("b", "urn:B"), ("c", "urn:Y"), ("d", "urn:D")]);
477 /// assert_eq!(
478 ///     vec![("a", "urn:Z"), ("c", "urn:C"), ("d", "urn:D"), ("b", "urn:B")],
479 ///     nst.iter().collect::<Vec<_>>()
480 /// );
481 /// ```
482 ///
483 /// Compare:
484 ///
485 /// ```
486 /// # use xml::namespace::NamespaceStack;
487 /// # let mut nst = NamespaceStack::empty();
488 /// # nst.push_empty();
489 /// # nst.put("a", "urn:A");
490 /// # nst.put("b", "urn:B");
491 /// # nst.push_empty();
492 /// # nst.put("c", "urn:C");
493 ///
494 /// nst.extend(vec![("a", "urn:Z"), ("b", "urn:B"), ("c", "urn:Y"), ("d", "urn:D")]);
495 /// assert_eq!(
496 ///     vec![("a", "urn:Z"), ("b", "urn:B"), ("c", "urn:C"), ("d", "urn:D")],
497 ///     nst.iter().collect::<Vec<_>>()
498 /// );
499 /// ```
500 pub struct CheckedTarget<'a>(&'a mut NamespaceStack);
501 
502 impl<'a, 'b> Extend<UriMapping<'b>> for CheckedTarget<'a> {
extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'b>>503     fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'b>> {
504         for (prefix, uri) in iterable {
505             self.0.put_checked(prefix, uri);
506         }
507     }
508 }
509