1use crate::prefixes::{Prefix, Prefixes};
11use crate::{Element, Error};
12use alloc::string::String;
13use alloc::vec::Vec;
14use rxml::{AttrMap, Namespace, RawEvent};
15
16pub struct TreeBuilder {
18 next_tag: Option<(Prefix, String, Prefixes, AttrMap)>,
19 stack: Vec<Element>,
21 prefixes_stack: Vec<Prefixes>,
23 attrs_stack: Vec<(String, String, String)>,
24 pub root: Option<Element>,
26}
27
28impl Default for TreeBuilder {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34impl TreeBuilder {
35 #[must_use]
37 pub fn new() -> Self {
38 TreeBuilder {
39 next_tag: None,
40 stack: Vec::new(),
41 prefixes_stack: Vec::new(),
42 attrs_stack: Vec::new(),
43 root: None,
44 }
45 }
46
47 #[must_use]
52 pub fn with_prefixes_stack(mut self, prefixes_stack: Vec<Prefixes>) -> Self {
53 self.prefixes_stack = prefixes_stack;
54 self
55 }
56
57 #[must_use]
59 pub fn depth(&self) -> usize {
60 self.stack.len()
61 }
62
63 #[must_use]
65 pub fn top(&mut self) -> Option<&Element> {
66 self.stack.last()
67 }
68
69 fn pop(&mut self) -> Option<Element> {
71 self.prefixes_stack.pop();
72 self.stack.pop()
73 }
74
75 pub fn unshift_child(&mut self) -> Option<Element> {
77 let depth = self.stack.len();
78 if depth > 0 {
79 self.stack[depth - 1].unshift_child()
80 } else {
81 None
82 }
83 }
84
85 #[must_use]
87 fn lookup_prefix<'a>(
88 prefixes_stack: &'a Vec<Prefixes>,
89 prefix: &'a Option<String>,
90 ) -> Option<&'a str> {
91 for nss in prefixes_stack.iter().rev() {
92 if let Some(ns) = nss.get(prefix) {
93 return Some(ns);
94 }
95 }
96
97 None
98 }
99
100 fn process_end_tag(&mut self) {
101 if let Some(el) = self.pop() {
102 if self.depth() > 0 {
103 let top = self.stack.len() - 1;
104 self.stack[top].append_child(el);
105 } else {
106 self.root = Some(el);
107 }
108 }
109 }
110
111 fn process_text(&mut self, text: String) {
112 if self.depth() > 0 {
113 let top = self.stack.len() - 1;
114 self.stack[top].append_text(text);
115 }
116 }
117
118 pub fn process_event(&mut self, event: RawEvent) -> Result<(), Error> {
120 match event {
121 RawEvent::XmlDeclaration(_, _) => {}
122
123 RawEvent::ElementHeadOpen(_, (prefix, name)) => {
124 let prefixes = if self.stack.is_empty() && self.prefixes_stack.len() == 1 {
127 self.prefixes_stack.pop().unwrap()
128 } else {
129 Prefixes::default()
130 };
131
132 self.next_tag = Some((
133 prefix.map(|prefix| prefix.as_str().to_owned()),
134 name.as_str().to_owned(),
135 prefixes,
136 AttrMap::new(),
137 ));
138 }
139
140 RawEvent::Attribute(_, (prefix, name), value) => {
141 if let Some((_, _, ref mut prefixes, ref mut attrs)) = self.next_tag.as_mut() {
142 match (prefix, name) {
143 (None, xmlns) if xmlns == "xmlns" => prefixes.insert(None, value),
144 (Some(xmlns), prefix) if xmlns.as_str() == "xmlns" => {
145 prefixes.insert(Some(prefix.as_str().to_owned()), value);
146 }
147 (Some(prefix), name) => {
148 self.attrs_stack
149 .push((prefix.to_string(), name.to_string(), value));
150 }
151 (None, name) => {
152 attrs.insert(
153 Namespace::NONE,
154 name.try_into().unwrap(),
155 value.as_str().to_owned(),
156 );
157 }
158 }
159 }
160 }
161
162 RawEvent::ElementHeadClose(_) => {
163 if let Some((prefix, name, prefixes, mut attrs)) = self.next_tag.take() {
164 self.prefixes_stack.push(prefixes.clone());
165
166 let namespace = TreeBuilder::lookup_prefix(
167 &self.prefixes_stack,
168 &prefix.map(|prefix| prefix.as_str().to_owned()),
169 )
170 .ok_or(Error::MissingNamespace)?
171 .to_owned();
172
173 for (prefix, attr, value) in self.attrs_stack.drain(..) {
174 let ns = if prefix == "xml" {
175 rxml::Namespace::xml()
176 } else {
177 &TreeBuilder::lookup_prefix(
178 &self.prefixes_stack,
179 &Some(prefix.to_string()),
180 )
181 .map(String::from)
182 .map(|s| TryInto::<Namespace>::try_into(s).unwrap())
183 .ok_or(Error::MissingNamespace)?
184 .to_owned()
185 };
186 attrs.insert(ns.clone(), attr.try_into().unwrap(), value.to_string());
187 }
188
189 let el = Element::new(name.to_owned(), namespace, prefixes, attrs, Vec::new());
190 self.stack.push(el);
191 }
192 }
193
194 RawEvent::ElementFoot(_) => self.process_end_tag(),
195
196 RawEvent::Text(_, text) => self.process_text(text.as_str().to_owned()),
197 }
198
199 Ok(())
200 }
201}