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