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