1use crate::names::Namespace;
22use crate::names::{NSMap, NSNameId, NSPrefixId, NSUriId};
23use std::collections::{HashMap, HashSet};
24
25pub struct NamespaceStackFrameIter<'frame> {
28 frame: &'frame NamespaceStackFrame,
29 i: usize,
30 n: usize,
31}
32
33impl<'frame> NamespaceStackFrameIter<'frame> {
35 fn new(frame: &'frame NamespaceStackFrame) -> Self {
36 let n = frame.order.len();
37 let i = 0;
38 Self { frame, n, i }
39 }
40}
41
42impl<'frame> Iterator for NamespaceStackFrameIter<'frame> {
44 type Item = NSMap;
45 fn next(&mut self) -> Option<Self::Item> {
46 if self.i >= self.n {
47 None
48 } else {
49 let prefix_id = self.frame.order[self.i];
50 self.i += 1;
51 if let Some(uri_id) = self.frame.find_mapping(prefix_id) {
52 let map = NSMap::new(prefix_id, *uri_id);
53 Some(map)
54 } else {
55 self.next()
56 }
57 }
58 }
59}
60
61#[derive(Default)]
63struct NamespaceStackFrame {
64 mappings: HashMap<NSPrefixId, NSUriId>,
65 order: Vec<NSPrefixId>,
66}
67
68impl NamespaceStackFrame {
70 pub fn add_mapping_by_id(&mut self, map: NSMap) {
72 self.mappings.insert(map.prefix_id(), map.uri_id());
73 }
74
75 pub fn add_mapping_by_id_if_unset(&mut self, map: NSMap) -> bool {
77 if self.mappings.contains_key(&map.prefix_id()) {
78 false
79 } else {
80 self.add_mapping_by_id(map);
81 true
82 }
83 }
84
85 fn find_mapping(&self, prefix_id: NSPrefixId) -> Option<&NSUriId> {
88 self.mappings.get(&prefix_id)
89 }
90
91 fn iter_mappings(&self) -> NamespaceStackFrameIter {
94 NamespaceStackFrameIter::new(self)
95 }
96}
97
98pub struct NamespaceStackIterator<'ns, 'b> {
100 stack: &'b NamespaceStack<'ns>,
101 frame: usize,
103 frame_iter: Option<std::collections::hash_map::Iter<'b, NSPrefixId, NSUriId>>,
105 used: HashSet<NSPrefixId>,
107}
108
109impl<'ns, 'b> NamespaceStackIterator<'ns, 'b> {
111 fn new(stack: &'b NamespaceStack<'ns>) -> Self {
112 let frame = stack.stack_depth();
113 let frame_iter = None;
114 let used = HashSet::new();
115 Self {
116 stack,
117 frame,
118 frame_iter,
119 used,
120 }
121 }
122}
123
124impl<'ns, 'b> Iterator for NamespaceStackIterator<'ns, 'b> {
126 type Item = NSMap;
127 fn next(&mut self) -> Option<Self::Item> {
128 if self.frame == 0 {
129 None
130 } else if let Some(iter) = &mut self.frame_iter {
131 if let Some((p_id, u_id)) = iter.next() {
132 if self.used.contains(p_id) {
133 self.next()
134 } else {
135 Some(NSMap::new(*p_id, *u_id))
136 }
137 } else {
138 self.frame -= 1;
139 self.frame_iter = None;
140 self.next()
141 }
142 } else {
143 self.frame_iter = Some(self.stack.borrow_frame(self.frame - 1).mappings.iter());
144 self.next()
145 }
146 }
147}
148
149pub struct NamespaceStack<'ns> {
183 namespaces: &'ns mut Namespace,
184 frames: Vec<NamespaceStackFrame>,
185}
186
187impl<'ns> NamespaceStack<'ns> {
189 pub fn new(namespaces: &'ns mut Namespace) -> Self {
193 let frames = vec![NamespaceStackFrame::default()];
194 let mut s = Self { namespaces, frames };
195 if s.uses_xmlns() {
196 s.add_default_xmls();
197 } else {
198 s.add_null_ns();
199 }
200 s
201 }
202
203 pub fn uses_xmlns(&self) -> bool {
207 self.namespaces.uses_xmlns()
208 }
209
210 pub fn add_null_ns(&mut self) {
215 self.add_ns("", "");
216 }
217
218 pub fn add_default_xmls(&mut self) {
223 self.add_null_ns();
224 self.add_ns("xmlns", "http://www.w3.org/2000/xmlns/");
225 self.add_ns("xml", "http://www.w3.org/XML/1998/namespace");
226 }
227
228 pub fn push_frame(&mut self) {
231 self.frames.push(NamespaceStackFrame::default());
232 }
233
234 pub fn pop_frame(&mut self) {
239 self.frames.pop().unwrap();
240 }
241
242 fn stack_depth(&self) -> usize {
245 self.frames.len()
246 }
247
248 fn borrow_frame(&self, n: usize) -> &NamespaceStackFrame {
251 &self.frames[n]
252 }
253
254 pub fn add_mapping_by_id(&mut self, map: NSMap) {
257 self.frames.last_mut().unwrap().add_mapping_by_id(map)
258 }
259
260 pub fn add_mapping_by_id_if_unset(&mut self, map: NSMap) -> bool {
263 self.frames
264 .last_mut()
265 .unwrap()
266 .add_mapping_by_id_if_unset(map)
267 }
268
269 pub fn find_mapping(&self, prefix_id: NSPrefixId) -> Option<NSUriId> {
275 let n = self.frames.len();
276 for i in 0..n {
277 if let Some(uri_id) = self.frames[n - 1 - i].find_mapping(prefix_id) {
278 return Some(*uri_id);
279 }
280 }
281 None
282 }
283
284 pub fn find_prefix_id(&mut self, prefix: &str) -> Option<NSPrefixId> {
288 self.namespaces.find_prefix(prefix)
289 }
290
291 pub fn iter_top_mappings(&self) -> NamespaceStackFrameIter<'_> {
294 assert!(self.frames.is_empty(), "Namespace stack cannot be empty");
295 self.frames.last().unwrap().iter_mappings()
296 }
297
298 pub fn borrow_mapping(&self, map: NSMap) -> (&str, &str) {
301 (self.prefix_str(map.prefix_id()), self.uri_str(map.uri_id()))
302 }
303
304 pub fn name_str(&self, name: NSNameId) -> &str {
307 self.namespaces.name_str(name, "")
308 }
309
310 pub fn prefix_str(&self, prefix: NSPrefixId) -> &str {
313 self.namespaces.prefix_str(prefix, "")
314 }
315
316 pub fn uri_str(&self, uri: NSUriId) -> &str {
319 self.namespaces.uri_str(uri, "")
320 }
321
322 pub fn add_name(&mut self, name: &str) -> NSNameId {
327 self.namespaces.find_or_add_name(name)
328 }
329
330 pub fn add_ns(&mut self, prefix: &str, uri: &str) -> NSMap {
333 let ns_map = self.namespaces.add_mapping(prefix, uri);
334 self.add_mapping_by_id(ns_map);
335 ns_map
336 }
337
338 pub fn add_ns_if_unset(&mut self, prefix: &str, uri: &str) -> (NSMap, bool) {
341 let ns_map = self.namespaces.add_mapping(prefix, uri);
342 (ns_map, self.add_mapping_by_id_if_unset(ns_map))
343 }
344
345 pub fn fmt_map<W: std::fmt::Write>(
348 &self,
349 w: &mut W,
350 map: NSMap,
351 ) -> Result<(), std::fmt::Error> {
352 write!(
353 w,
354 "'{}' => '{}'",
355 self.prefix_str(map.prefix_id()),
356 self.uri_str(map.uri_id())
357 )
358 }
359
360 }
362
363impl<'ns, 'b> IntoIterator for &'b NamespaceStack<'ns> {
365 type Item = NSMap;
366 type IntoIter = NamespaceStackIterator<'ns, 'b>;
367
368 fn into_iter(self) -> Self::IntoIter {
369 NamespaceStackIterator::new(self)
370 }
371}
372
373#[cfg(test)]
375mod test {
376 use crate::names::{Namespace, NamespaceStack};
377 fn dump_namespace(nst: &NamespaceStack) {
378 for i in nst {
379 let mut s = String::new();
380 nst.fmt_map(&mut s, i).unwrap();
381 println!("{}", s);
382 }
383 }
384 #[test]
385 fn test_defaults() {
386 let mut ns = Namespace::new(false);
387 let mut nst = NamespaceStack::new(&mut ns);
388
389 nst.add_default_xmls();
390
391 assert_eq!(nst.into_iter().count(), 3);
392
393 let pid = nst.find_prefix_id("").unwrap();
394 assert!(pid.is_none());
395 assert_eq!(nst.prefix_str(pid), "");
396 assert_eq!(nst.uri_str(nst.find_mapping(pid).unwrap()), "");
397
398 let pid = nst.find_prefix_id("xml").unwrap();
399 assert_eq!(nst.prefix_str(pid), "xml");
400 assert_eq!(
401 nst.uri_str(nst.find_mapping(pid).unwrap()),
402 "http://www.w3.org/XML/1998/namespace"
403 );
404
405 let pid = nst.find_prefix_id("xmlns").unwrap();
406 assert_eq!(nst.prefix_str(pid), "xmlns");
407 assert_eq!(
408 nst.uri_str(nst.find_mapping(pid).unwrap()),
409 "http://www.w3.org/2000/xmlns/"
410 );
411
412 let pid = nst.find_prefix_id("fred");
413 assert_eq!(pid, None);
414
415 nst.push_frame();
416
417 nst.add_ns("fred", "http://fred.com");
418 assert_eq!(nst.into_iter().count(), 4);
419
420 let pid = nst.find_prefix_id("fred").unwrap();
421 assert_eq!(nst.prefix_str(pid), "fred");
422 assert_eq!(
423 nst.uri_str(nst.find_mapping(pid).unwrap()),
424 "http://fred.com"
425 );
426
427 nst.add_ns_if_unset("fred", "http://NOTfred.com");
428 assert_eq!(
429 nst.uri_str(nst.find_mapping(pid).unwrap()),
430 "http://fred.com"
431 );
432
433 nst.add_ns("fred", "http://fred2.com");
434 assert_eq!(
435 nst.uri_str(nst.find_mapping(pid).unwrap()),
436 "http://fred2.com"
437 );
438
439 nst.add_ns("xml", "http://xml_override");
440 let pid = nst.find_prefix_id("xml").unwrap();
441 assert_eq!(nst.prefix_str(pid), "xml");
442 assert_eq!(
443 nst.uri_str(nst.find_mapping(pid).unwrap()),
444 "http://xml_override"
445 );
446
447 dump_namespace(&nst);
448
449 nst.pop_frame();
450
451 assert_eq!(nst.into_iter().count(), 3);
452
453 let pid = nst.find_prefix_id("").unwrap();
454 assert!(pid.is_none());
455 assert_eq!(nst.prefix_str(pid), "");
456 assert_eq!(nst.uri_str(nst.find_mapping(pid).unwrap()), "");
457
458 let pid = nst.find_prefix_id("xml").unwrap();
459 assert_eq!(nst.prefix_str(pid), "xml");
460 assert_eq!(
461 nst.uri_str(nst.find_mapping(pid).unwrap()),
462 "http://www.w3.org/XML/1998/namespace"
463 );
464
465 let pid = nst.find_prefix_id("xmlns").unwrap();
466 assert_eq!(nst.prefix_str(pid), "xmlns");
467 assert_eq!(
468 nst.uri_str(nst.find_mapping(pid).unwrap()),
469 "http://www.w3.org/2000/xmlns/"
470 );
471
472 let pid = nst.find_prefix_id("fred").unwrap(); assert_eq!(nst.find_mapping(pid), None);
474 }
475}