1// Copyright (c) 2022 Astro <astro@spaceboyz.net>
2
3//! SAX events to DOM tree conversion
4
5use crate::prefixes::{Prefix, Prefixes};
6use crate::{Element, Error};
7use rxml::RawEvent;
8use std::collections::BTreeMap;
9
10/// Tree-building parser state
11pub struct TreeBuilder {
12 next_tag: Option<(Prefix, String, Prefixes, BTreeMap<String, String>)>,
13 /// Parsing stack
14 stack: Vec<Element>,
15 /// Namespace set stack by prefix
16 prefixes_stack: Vec<Prefixes>,
17 /// Document root element if finished
18 pub root: Option<Element>,
19}
20
21impl TreeBuilder {
22 /// Create a new one
23 pub fn new() -> Self {
24 TreeBuilder {
25 next_tag: None,
26 stack: vec![],
27 prefixes_stack: vec![],
28 root: None,
29 }
30 }
31
32 /// Allow setting prefixes stack.
33 ///
34 /// Useful to provide knowledge of namespaces that would have been declared on parent elements
35 /// not present in the reader.
36 pub fn with_prefixes_stack(mut self, prefixes_stack: Vec<Prefixes>) -> Self {
37 self.prefixes_stack = prefixes_stack;
38 self
39 }
40
41 /// Stack depth
42 pub fn depth(&self) -> usize {
43 self.stack.len()
44 }
45
46 /// Get the top-most element from the stack but don't remove it
47 pub fn top(&mut self) -> Option<&Element> {
48 self.stack.last()
49 }
50
51 /// Pop the top-most element from the stack
52 fn pop(&mut self) -> Option<Element> {
53 self.prefixes_stack.pop();
54 self.stack.pop()
55 }
56
57 /// Unshift the first child of the top element
58 pub fn unshift_child(&mut self) -> Option<Element> {
59 let depth = self.stack.len();
60 if depth > 0 {
61 self.stack[depth - 1].unshift_child()
62 } else {
63 None
64 }
65 }
66
67 /// Lookup XML namespace declaration for given prefix (or no prefix)
68 fn lookup_prefix(&self, prefix: &Option<String>) -> Option<&str> {
69 for nss in self.prefixes_stack.iter().rev() {
70 if let Some(ns) = nss.get(prefix) {
71 return Some(ns);
72 }
73 }
74
75 None
76 }
77
78 fn process_end_tag(&mut self) -> Result<(), Error> {
79 if let Some(el) = self.pop() {
80 if self.depth() > 0 {
81 let top = self.stack.len() - 1;
82 self.stack[top].append_child(el);
83 } else {
84 self.root = Some(el);
85 }
86 }
87
88 Ok(())
89 }
90
91 fn process_text(&mut self, text: String) {
92 if self.depth() > 0 {
93 let top = self.stack.len() - 1;
94 self.stack[top].append_text_node(text);
95 }
96 }
97
98 /// Process a Event that you got out of a RawParser
99 pub fn process_event(&mut self, event: RawEvent) -> Result<(), Error> {
100 match event {
101 RawEvent::XmlDeclaration(_, _) => {}
102
103 RawEvent::ElementHeadOpen(_, (prefix, name)) => {
104 self.next_tag = Some((
105 prefix.map(|prefix| prefix.as_str().to_owned()),
106 name.as_str().to_owned(),
107 Prefixes::default(),
108 BTreeMap::new(),
109 ))
110 }
111
112 RawEvent::Attribute(_, (prefix, name), value) => {
113 self.next_tag
114 .as_mut()
115 .map(
116 |(_, _, ref mut prefixes, ref mut attrs)| match (prefix, name) {
117 (None, xmlns) if xmlns == "xmlns" => {
118 prefixes.insert(None, value);
119 }
120 (Some(xmlns), prefix) if xmlns.as_str() == "xmlns" => {
121 prefixes.insert(Some(prefix.as_str().to_owned()), value);
122 }
123 (Some(prefix), name) => {
124 attrs.insert(
125 format!("{}:{}", prefix, name),
126 value.as_str().to_owned(),
127 );
128 }
129 (None, name) => {
130 attrs.insert(name.as_str().to_owned(), value.as_str().to_owned());
131 }
132 },
133 );
134 }
135
136 RawEvent::ElementHeadClose(_) => {
137 if let Some((prefix, name, prefixes, attrs)) = self.next_tag.take() {
138 self.prefixes_stack.push(prefixes.clone());
139
140 let namespace = self
141 .lookup_prefix(&prefix.clone().map(|prefix| prefix.as_str().to_owned()))
142 .ok_or(Error::MissingNamespace)?
143 .to_owned();
144 let el =
145 Element::new(name.as_str().to_owned(), namespace, prefixes, attrs, vec![]);
146 self.stack.push(el);
147 }
148 }
149
150 RawEvent::ElementFoot(_) => self.process_end_tag()?,
151
152 RawEvent::Text(_, text) => self.process_text(text.as_str().to_owned()),
153 }
154
155 Ok(())
156 }
157}