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() -> Namespace {
77 Namespace(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)| 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]
110 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.
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.
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.
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]
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.
178pub type NamespaceMappings<'a> = Map<
179 Entries<'a, String, String>,
180 for<'b> fn((&'b String, &'b String)) -> UriMapping<'b>
181>;
182
183impl<'a> IntoIterator for &'a Namespace {
184 type Item = UriMapping<'a>;
185 type IntoIter = NamespaceMappings<'a>;
186
187 fn into_iter(self) -> Self::IntoIter {
188 fn mapper<'a>((prefix: &String, uri: &String): (&'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)]
200pub struct NamespaceStack(pub Vec<Namespace>);
201
202impl NamespaceStack {
203 /// Returns an empty namespace stack.
204 #[inline]
205 #[must_use]
206 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]
218 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]
232 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]
241 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]
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]
257 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]
266 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.
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]
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]
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]
346 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]
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]
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/// ```
384pub struct NamespaceStackMappings<'a> {
385 namespaces: Rev<Iter<'a, Namespace>>,
386 current_namespace: Option<NamespaceMappings<'a>>,
387 used_keys: HashSet<&'a str>,
388}
389
390impl<'a> NamespaceStackMappings<'a> {
391 fn go_to_next_namespace(&mut self) -> bool {
392 self.current_namespace = self.namespaces.next().map(|ns: &Namespace| ns.into_iter());
393 self.current_namespace.is_some()
394 }
395}
396
397impl<'a> Iterator for NamespaceStackMappings<'a> {
398 type Item = UriMapping<'a>;
399
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
430impl<'a> IntoIterator for &'a NamespaceStack {
431 type Item = UriMapping<'a>;
432 type IntoIter = NamespaceStackMappings<'a>;
433
434 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.
444pub type UriMapping<'a> = (&'a str, &'a str);
445
446impl<'a> Extend<UriMapping<'a>> for Namespace {
447 fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>> {
448 for (prefix: &str, uri: &str) in iterable {
449 self.put(prefix, uri);
450 }
451 }
452}
453
454impl<'a> Extend<UriMapping<'a>> for NamespaceStack {
455 fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>> {
456 for (prefix: &str, uri: &str) 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/// ```
500pub struct CheckedTarget<'a>(&'a mut NamespaceStack);
501
502impl<'a, 'b> Extend<UriMapping<'b>> for CheckedTarget<'a> {
503 fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'b>> {
504 for (prefix: &str, uri: &str) in iterable {
505 self.0.put_checked(prefix, uri);
506 }
507 }
508}
509