1use crate::schema::XmlSchema;
3use std::fmt::Write;
4use std::collections::HashMap;
5
6#[derive(Debug)]
7struct Element {
8 position: Vec<usize>,
9 value: String,
10 cdata: bool,
11
12}
13
14
15pub(crate) struct Builder {
16 elements: Vec<Element>,
17 schema: XmlSchema,
18 current_key: Vec<usize>,
19 key_list: HashMap::<(usize,String),usize>,
21 key_count: usize,
22 pub xml_output: String,
23 attribute_list: HashMap::<(usize,usize),String>,
24
25 headers: Vec<String>,
26 ind_original_header: bool,
27
28
29
30}
31
32pub struct ChainFromAdd<'a>
33{
34 builder: &'a mut Builder,
35 no_element: usize,
36 no_key: usize
37
38
39}
40
41impl<'a> ChainFromAdd<'a> {
42 pub(crate) fn attributes(self, attributes: &[(&str, &str)]) {
43 let mut all_attributes = String::new();
45 for &(att, value) in attributes {
46 write!(all_attributes, " {}=\"{}\"", att, value).unwrap();
47 }
48
49 match self.builder.attribute_list.get(&(self.no_element, self.no_key)) {
50 Some(value) => {
51 if &all_attributes != value {
52 panic!("Tried to add a second set of attributes to the same key/element");
53 }
54 }
56 None => {
57 self.builder
58 .attribute_list
59 .insert((self.no_element, self.no_key), all_attributes.clone());
60 }
61 }
62 }
63
64 pub fn attribute<V: ToString>(self, name: &str, value: V) {
65 let mut all_attributes = String::new();
67 let value_quoted = format!("\"{}\"", value.to_string());
68 let combined = format!(" {}={}", name, value_quoted);
69 all_attributes.push_str(&combined);
70 match self.builder.attribute_list.get(&(self.no_element, self.no_key)) {
71 Some(existing) => {
72 if &all_attributes != existing {
73 panic!("Tried to add a second set of attributes to the same key/element");
74 }
75 },
77 None => {
78 self.builder.attribute_list.insert((self.no_element, self.no_key), all_attributes.clone());
79 }
80 }
81 }
82
83 pub fn cdata(self) -> Self {
84
85 self.builder.elements.last_mut().unwrap().cdata = true;
86 self
87 }
88}
89
90
91
92
93
94
95
96
97
98
99impl Builder {
100
101
102
103 pub(crate) fn clear_headers(&mut self) {
104 self.headers.clear();
105 }
106
107 pub(crate) fn custom_header(&mut self, headers: &str) {
108 if self.ind_original_header == true
109 { self.headers.clear(); }
110 self.headers.push(format!("<?{}?>", headers));
111 self.ind_original_header = false;
112 }
113
114
115
116 pub(crate) fn new() -> Self
117 {
118
119 Self {
120 elements: vec![Element { position: Vec::new(), value: "".to_string(), cdata: false }],
121 schema: XmlSchema::new(),
122 current_key: Vec::new(),
123 key_list: HashMap::new(),
124 key_count: 0,
125 xml_output: String::new(),
126 attribute_list: HashMap::new(),
127 headers: vec!["<?xml version=\"1.0\" encoding=\"UTF-8\"?>".to_string()],
128 ind_original_header: true,
129 }
130 }
131
132 pub(crate) fn set_schema(&mut self,txt_schema: &str)
133 {
134 self.schema.set_schema(txt_schema);
135 self.schema.parse_schema();
136 self.current_key.resize(self.schema.element_no_lookup.len(), 0);
137 }
138
139 pub(crate) fn get_position(&self,nm_element: &str) -> &Vec<usize>
140 {
141 self.schema.element_no_lookup
142 .get(nm_element)
143 .expect("Tried to add an element that does not exist in the schema")
144 }
145
146
147
148 #[allow(unused_must_use)]
149 pub(crate) fn set_key(&mut self, nm_element: &str, txt_key: &str) -> ChainFromAdd {
150 let position = self.get_position(nm_element);
151 let &no_element = position.last().unwrap();
152 let returned_key: usize;
153 if let Some(&existing) = self.key_list.get(&(no_element, txt_key.to_string())) {
154 self.current_key[no_element] = existing;
155 returned_key = existing;
156 } else {
157 self.key_count += 1;
158 self.key_list.insert((no_element, txt_key.to_string()), self.key_count);
159 self.current_key[no_element] = self.key_count;
160 returned_key = self.key_count;
161 }
162 ChainFromAdd { builder: self, no_element, no_key: returned_key }
163 }
164
165
166
167 pub(crate) fn clear_key(&mut self)
168 {
169 self.current_key.fill(0) ;
170 }
171
172 #[allow(unused_must_use)]
173 pub(crate) fn add_element(&mut self, nm_element: &str, value_element: &str) -> ChainFromAdd {
174 self.key_count += 1;
175 let key_count = self.key_count;
176 let final_value = if value_element.is_empty() {
177 " ".to_string()
178 } else {
179 value_element.to_string()
180 };
181 let (positition_and_key, element_number) = {
182 let position = self.get_position(nm_element);
183 (create_position(&position, &self.current_key), *position.last().unwrap())
184 };
185 self.elements.push(Element { position: positition_and_key, value: final_value, cdata: false });
186 ChainFromAdd { builder: self, no_element: element_number, no_key: key_count }
187 }
188
189 pub(crate) fn build_xml(&mut self)
192 {
193
194 for i in &self.headers {
195 write!(self.xml_output, "{}\n", i).unwrap();
196 }
197
198 for i in &mut self.schema.element_names {
199 *i = i.split('!').next().unwrap().to_string();
200 }
201 self.elements.sort_unstable_by(|a, b| a.position.cmp(&b.position));
204 self.elements.push(Element { position: Vec::new(), value: "".to_string(), cdata: false });
205
206 let mut opening_tags: Vec<(usize,usize,usize)> = Vec::new();
207for n in 1..self.elements.len() {
208 let last = &self.elements[n - 1];
209 let current = &self.elements[n];
210 let len = last.position.len().max(current.position.len());
214
215 opening_tags.clear();
219
220 for i in (0..len/2).rev() {
221
222
223 let l = (last.position.get(2*i),last.position.get(2*i+1));
224 let c = (current.position.get(2*i),current.position.get(2*i+1));
225
226 if l != c && l.0 != None {
230
231 let elem_name = &self.schema.element_names[*l.0.unwrap()];
232
233 let indent = if i == last.position.len()/2 - 1 {
234 "".to_string()
235} else {
236 " ".repeat(i)
237};
238
239
240
241 write!(self.xml_output, "{}</{}>\n", indent, elem_name).unwrap();
242 }
245 if l != c && c.0 != None { opening_tags.push((*c.0.unwrap(),*c.1.unwrap(),i)) ; }
247
248 }
249
250 for &n in opening_tags.iter().skip(1).rev() {
253
254 let elem_name = &self.schema.element_names[n.0];
255
256
257 let attribute = self.attribute_list.get(&(n.0,n.1)) ;
259
260
261
262 let open_tag = format!("{}<{}{}>\n", " ".repeat(n.2), elem_name, attribute.unwrap_or(&"".to_string()));
263 self.xml_output.push_str(&open_tag);
264 }
266
267if !current.value.is_empty() {
270 let elem_name = &self.schema.element_names[opening_tags[0].0];
271 let attribute = &self.attribute_list.get(&(opening_tags[0].0,opening_tags[0].1)) ;
272
273 if self.elements[n].cdata {
274 write!(
275 self.xml_output,
276 "{}<{}{}><![CDATA[{}]]>",
277 " ".repeat(opening_tags.first().unwrap().2),
278 elem_name,
279 attribute.unwrap_or(&"".to_string()),
280 self.elements[n].value
281
282 ).unwrap();
283 } else {
284 write!(
285 self.xml_output,
286 "{}<{}{}>{}",
287 " ".repeat(opening_tags.first().unwrap().2),
288 elem_name,
289 attribute.unwrap_or(&"".to_string()),
290 escape_xml(&self.elements[n].value)
291
292 ).unwrap();
293 }
294 }
297
298
299 }
300
301
302 }
303}
304
305
306fn escape_xml(input: &str) -> String {
307 let mut escaped = String::with_capacity(input.len());
308 for c in input.chars() {
309 match c {
310 '&' => escaped.push_str("&"),
311 '<' => escaped.push_str("<"),
312 '>' => escaped.push_str(">"),
313 '"' => escaped.push_str("""),
314 '\'' => escaped.push_str("'"),
315 _ => escaped.push(c),
316 }
317 }
318 escaped
319}
320
321
322
323
324 fn create_position(position: &Vec<usize>, key: &Vec<usize>) -> Vec<usize> {
325 let len = position.len().max(key.len());
326 let mut combined = Vec::with_capacity(len * 2);
327 for i in position {
328
329 let key_val = *key.get(*i).unwrap();
330 combined.push(*i);
332 combined.push(key_val);
333 }
335 combined
336}
337
338
339
340
341
342#[cfg(test)]
343mod tests {
344 use super::*;
345#[test]
363 fn test_set_key()
364 {
365 let mut xb: Builder = Builder::new();
366 xb.set_schema(
367 "<root>
368 <g1></g1>
369 <g2><g3><g4></g4></g3></g2></root>");
370
371 for i in &xb.schema.element_no_lookup
372 {
373 println!("{:?}",i);
374 }
375 xb.set_key("g2", "1");
376 println!("{:?}",xb.current_key);
377 xb.set_key("g2", "1");
378 println!("{:?}",xb.current_key);
379 xb.set_key("g2", "2");
380 println!("{:?}",xb.current_key);
381
382 xb.set_key("g1", "1");
383 println!("{:?}",xb.current_key);
384 xb.set_key("g1", "1");
385 println!("{:?}",xb.current_key);
386 xb.set_key("g1", "2");
387 println!("{:?}",xb.current_key);
388
389 xb.set_key("g2", "3");
390 println!("{:?}",xb.current_key);
391 xb.set_key("g2", "4");
392 println!("{:?}",xb.current_key);
393
394 xb.set_key("g4", "1");
395 println!("{:?}",xb.current_key);
396
397 xb.set_key("root", "0");
398 println!("{:?}",xb.current_key);
399
400 xb.add_element("g4", "999");
401 println!("{:?}",xb.elements[0] );
402
403 xb.clear_key();
404 println!("{:?}",xb.current_key);
405
406
407 xb.build_xml();
408
409
410
411
412 }
413
414
415}