• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Contains namespace manipulation types and functions.
2 
3 use std::iter::{Map, Rev};
4 use std::collections::btree_map::{BTreeMap, Entry};
5 use std::collections::btree_map::Iter as Entries;
6 use std::collections::HashSet;
7 use 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
14 pub 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/
21 pub 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/
32 pub 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.
37 pub 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).
55 pub 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.
63 pub 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)]
69 pub struct Namespace(pub BTreeMap<String, String>);
70 
71 impl Namespace {
72     /// Returns an empty namespace.
73     #[inline]
empty() -> Namespace74     pub fn empty() -> Namespace { Namespace(BTreeMap::new()) }
75 
76     /// Checks whether this namespace is empty.
77     #[inline]
is_empty(&self) -> bool78     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.
is_essentially_empty(&self) -> bool84     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]
contains<P: ?Sized+AsRef<str>>(&self, prefix: &P) -> bool104     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.
put<P, U>(&mut self, prefix: P, uri: U) -> bool where P: Into<String>, U: Into<String>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.
force_put<P, U>(&mut self, prefix: P, uri: U) -> Option<String> where P: Into<String>, U: Into<String>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.
get<'a, P: ?Sized+AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str>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.
166 pub type NamespaceMappings<'a> = Map<
167     Entries<'a, String, String>,
168     for<'b> fn((&'b String, &'b String)) -> UriMapping<'b>
169 >;
170 
171 impl<'a> IntoIterator for &'a Namespace {
172     type Item = UriMapping<'a>;
173     type IntoIter = NamespaceMappings<'a>;
174 
into_iter(self) -> Self::IntoIter175     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)]
188 pub struct NamespaceStack(pub Vec<Namespace>);
189 
190 impl NamespaceStack {
191     /// Returns an empty namespace stack.
192     #[inline]
empty() -> NamespaceStack193     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]
default() -> NamespaceStack202     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]
push_empty(&mut self) -> &mut NamespaceStack216     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]
pop(&mut self) -> Namespace225     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]
try_pop(&mut self) -> Option<Namespace>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]
peek_mut(&mut self) -> &mut Namespace241     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]
peek(&self) -> &Namespace249     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.
put_checked<P, U>(&mut self, prefix: P, uri: U) -> bool where P: Into<String> + AsRef<str>, U: Into<String> + AsRef<str>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]
put<P, U>(&mut self, prefix: P, uri: U) -> bool where P: Into<String>, U: Into<String>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]
get<'a, P: ?Sized+AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str>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.
squash(&self) -> Namespace324     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]
checked_target(&mut self) -> CheckedTarget336     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]
iter(&self) -> NamespaceStackMappings342     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 /// ```
361 pub struct NamespaceStackMappings<'a> {
362     namespaces: Rev<Iter<'a, Namespace>>,
363     current_namespace: Option<NamespaceMappings<'a>>,
364     used_keys: HashSet<&'a str>
365 }
366 
367 impl<'a> NamespaceStackMappings<'a> {
go_to_next_namespace(&mut self) -> bool368     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 
374 impl<'a> Iterator for NamespaceStackMappings<'a> {
375     type Item = UriMapping<'a>;
376 
next(&mut self) -> Option<UriMapping<'a>>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 
407 impl<'a> IntoIterator for &'a NamespaceStack {
408     type Item = UriMapping<'a>;
409     type IntoIter = NamespaceStackMappings<'a>;
410 
into_iter(self) -> Self::IntoIter411     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.
421 pub type UriMapping<'a> = (&'a str, &'a str);
422 
423 impl<'a> Extend<UriMapping<'a>> for Namespace {
extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>>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 
431 impl<'a> Extend<UriMapping<'a>> for NamespaceStack {
extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>>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 /// ```
477 pub struct CheckedTarget<'a>(&'a mut NamespaceStack);
478 
479 impl<'a, 'b> Extend<UriMapping<'b>> for CheckedTarget<'a> {
extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'b>>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 }
486