1use std::fs::File;
36use std::io::Write;
37
38pub struct XMLWriter<'a> {
39 xmlfile: &'a File,
40}
41
42impl<'a> XMLWriter<'a> {
43 pub fn new(xmlfile: &File) -> XMLWriter {
56 XMLWriter { xmlfile }
57 }
58
59 pub fn xml_declaration(&mut self) {
75 writeln!(
76 &mut self.xmlfile,
77 r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>"#
78 )
79 .expect("Couldn't write to file");
80 }
81
82 pub fn xml_start_tag(&mut self, tag: &str, attributes: &Vec<(&str, &str)>) {
99 let mut attribute_str = String::from("");
100
101 for attribute in attributes {
102 let pair = format!(r#" {}="{}""#, attribute.0, escape_attributes(attribute.1));
103 attribute_str.push_str(&pair);
104 }
105
106 write!(&mut self.xmlfile, r"<{}{}>", tag, attribute_str).expect("Couldn't write to file");
107 }
108
109 pub fn xml_end_tag(&mut self, tag: &str) {
126 write!(&mut self.xmlfile, r"</{}>", tag).expect("Couldn't write to file");
127 }
128
129 pub fn xml_empty_tag(&mut self, tag: &str, attributes: &Vec<(&str, &str)>) {
146 let mut attribute_str = String::from("");
147
148 for attribute in attributes {
149 let pair = format!(r#" {}="{}""#, attribute.0, escape_attributes(attribute.1));
150 attribute_str.push_str(&pair);
151 }
152
153 write!(&mut self.xmlfile, r"<{}{}/>", tag, attribute_str).expect("Couldn't write to file");
154 }
155
156 pub fn xml_data_element(&mut self, tag: &str, data: &str, attributes: &Vec<(&str, &str)>) {
173 let mut attribute_str = String::from("");
174
175 for attribute in attributes {
176 let pair = format!(r#" {}="{}""#, attribute.0, escape_attributes(attribute.1));
177 attribute_str.push_str(&pair);
178 }
179
180 write!(
181 &mut self.xmlfile,
182 r"<{}{}>{}</{}>",
183 tag,
184 attribute_str,
185 escape_data(data),
186 tag
187 )
188 .expect("Couldn't write to file");
189 }
190
191 pub fn xml_string_element(&mut self, index: u32, attributes: &Vec<(&str, &str)>) {
193 let mut attribute_str = String::from("");
194
195 for attribute in attributes {
196 let pair = format!(r#" {}="{}""#, attribute.0, escape_attributes(attribute.1));
197 attribute_str.push_str(&pair);
198 }
199
200 write!(
201 &mut self.xmlfile,
202 r#"<c{} t="s"><v>{}</v></c>"#,
203 attribute_str, index
204 )
205 .expect("Couldn't write to file");
206 }
207
208 pub fn xml_number_element(&mut self, number: f64, attributes: &Vec<(&str, &str)>) {
210 let mut attribute_str = String::from("");
212
213 for attribute in attributes {
214 let pair = format!(r#" {}="{}""#, attribute.0, escape_attributes(attribute.1));
215 attribute_str.push_str(&pair);
216 }
217
218 write!(
219 &mut self.xmlfile,
220 r#"<c{} t="s"><v>{}</v></c>"#,
221 attribute_str, number
222 )
223 .expect("Couldn't write to file");
224 }
225
226 pub fn xml_formula_element(
228 &mut self,
229 formula: &str,
230 result: f64,
231 attributes: &Vec<(&str, &str)>,
232 ) {
233 let mut attribute_str = String::from("");
234
235 for attribute in attributes {
236 let pair = format!(r#" {}="{}""#, attribute.0, escape_attributes(attribute.1));
237 attribute_str.push_str(&pair);
238 }
239
240 write!(
241 &mut self.xmlfile,
242 r#"<c{}><f>{}</f><v>{}</v></c>"#,
243 attribute_str,
244 escape_data(formula),
245 result
246 )
247 .expect("Couldn't write to file");
248 }
249
250 pub fn xml_si_element(&mut self, string: &str, attributes: &Vec<(&str, &str)>) {
252 let mut attribute_str = String::from("");
253
254 for attribute in attributes {
255 let pair = format!(r#" {}="{}""#, attribute.0, escape_attributes(attribute.1));
256 attribute_str.push_str(&pair);
257 }
258
259 write!(
260 &mut self.xmlfile,
261 r#"<si><t{}>{}</t></si>"#,
262 attribute_str,
263 escape_data(string)
264 )
265 .expect("Couldn't write to file");
266 }
267
268 pub fn xml_rich_si_element(&mut self, string: &str) {
270 write!(&mut self.xmlfile, r#"<si>{}</si>"#, string).expect("Couldn't write to file");
271 }
272}
273
274fn escape_attributes(attribute: &str) -> String {
276 attribute
277 .replace('&', "&")
278 .replace('"', """)
279 .replace('<', "<")
280 .replace('>', ">")
281 .replace('\n', "
")
282}
283
284fn escape_data(attribute: &str) -> String {
288 attribute
289 .replace('&', "&")
290 .replace('<', "<")
291 .replace('>', ">")
292}
293
294#[cfg(test)]
295mod tests {
296
297 use super::XMLWriter;
298 use std::fs::File;
299 use std::io::{Read, Seek, SeekFrom};
300 use tempfile::tempfile;
301
302 use pretty_assertions::assert_eq;
303
304 fn read_xmlfile_data(tempfile: &mut File) -> String {
305 let mut got = String::new();
306 tempfile.seek(SeekFrom::Start(0)).unwrap();
307 tempfile.read_to_string(&mut got).unwrap();
308 got
309 }
310
311 #[test]
312 fn test_xml_declaration() {
313 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
314
315 let mut tempfile = tempfile().unwrap();
316 let mut writer = XMLWriter::new(&tempfile);
317
318 writer.xml_declaration();
319
320 let got = read_xmlfile_data(&mut tempfile);
321 assert_eq!(got, expected);
322 }
323
324 #[test]
325 fn test_xml_start_tag() {
326 let expected = "<foo>";
327 let attributes = vec![];
328
329 let mut tempfile = tempfile().unwrap();
330 let mut writer = XMLWriter::new(&tempfile);
331
332 writer.xml_start_tag("foo", &attributes);
333
334 let got = read_xmlfile_data(&mut tempfile);
335 assert_eq!(got, expected);
336 }
337
338 #[test]
339 fn test_xml_start_tag_with_attributes() {
340 let expected = r#"<foo span="8" baz="7">"#;
341 let attributes = vec![("span", "8"), ("baz", "7")];
342
343 let mut tempfile = tempfile().unwrap();
344 let mut writer = XMLWriter::new(&tempfile);
345
346 writer.xml_start_tag("foo", &attributes);
347
348 let got = read_xmlfile_data(&mut tempfile);
349 assert_eq!(got, expected);
350 }
351
352 #[test]
353 fn test_xml_end_tag() {
354 let expected = "</foo>";
355
356 let mut tempfile = tempfile().unwrap();
357 let mut writer = XMLWriter::new(&tempfile);
358
359 writer.xml_end_tag("foo");
360
361 let got = read_xmlfile_data(&mut tempfile);
362 assert_eq!(got, expected);
363 }
364
365 #[test]
366 fn test_xml_empty_tag() {
367 let expected = "<foo/>";
368 let attributes = vec![];
369
370 let mut tempfile = tempfile().unwrap();
371 let mut writer = XMLWriter::new(&tempfile);
372
373 writer.xml_empty_tag("foo", &attributes);
374
375 let got = read_xmlfile_data(&mut tempfile);
376 assert_eq!(got, expected);
377 }
378
379 #[test]
380 fn test_xml_empty_tag_with_attributes() {
381 let expected = r#"<foo span="8"/>"#;
382 let attributes = vec![("span", "8")];
383
384 let mut tempfile = tempfile().unwrap();
385 let mut writer = XMLWriter::new(&tempfile);
386
387 writer.xml_empty_tag("foo", &attributes);
388
389 let got = read_xmlfile_data(&mut tempfile);
390 assert_eq!(got, expected);
391 }
392
393 #[test]
394 fn test_xml_data_element() {
395 let expected = r#"<foo>bar</foo>"#;
396 let attributes = vec![];
397
398 let mut tempfile = tempfile().unwrap();
399 let mut writer = XMLWriter::new(&tempfile);
400
401 writer.xml_data_element("foo", "bar", &attributes);
402
403 let got = read_xmlfile_data(&mut tempfile);
404 assert_eq!(got, expected);
405 }
406
407 #[test]
408 fn test_xml_data_element_with_attributes() {
409 let expected = r#"<foo span="8">bar</foo>"#;
410 let attributes = vec![("span", "8")];
411
412 let mut tempfile = tempfile().unwrap();
413 let mut writer = XMLWriter::new(&tempfile);
414
415 writer.xml_data_element("foo", "bar", &attributes);
416
417 let got = read_xmlfile_data(&mut tempfile);
418 assert_eq!(got, expected);
419 }
420
421 #[test]
422 fn test_xml_data_element_with_escapes() {
423 let expected = r#"<foo span="8">&<>"</foo>"#;
424 let attributes = vec![("span", "8")];
425
426 let mut tempfile = tempfile().unwrap();
427 let mut writer = XMLWriter::new(&tempfile);
428
429 writer.xml_data_element("foo", "&<>\"", &attributes);
430
431 let got = read_xmlfile_data(&mut tempfile);
432 assert_eq!(got, expected);
433 }
434
435 #[test]
436 fn test_xml_string_element() {
437 let expected = r#"<c span="8" t="s"><v>99</v></c>"#;
438 let attributes = vec![("span", "8")];
439
440 let mut tempfile = tempfile().unwrap();
441 let mut writer = XMLWriter::new(&tempfile);
442
443 writer.xml_string_element(99, &attributes);
444
445 let got = read_xmlfile_data(&mut tempfile);
446 assert_eq!(got, expected);
447 }
448
449 #[test]
450 fn test_xml_number_element() {
451 let expected = r#"<c span="8" t="s"><v>99</v></c>"#;
452 let attributes = vec![("span", "8")];
453
454 let mut tempfile = tempfile().unwrap();
455 let mut writer = XMLWriter::new(&tempfile);
456
457 writer.xml_number_element(99.0, &attributes);
458
459 let got = read_xmlfile_data(&mut tempfile);
460 assert_eq!(got, expected);
461 }
462
463 #[test]
464 fn test_xml_formula_element() {
465 let expected = r#"<c span="8"><f>1+2</f><v>3</v></c>"#;
466 let attributes = vec![("span", "8")];
467
468 let mut tempfile = tempfile().unwrap();
469 let mut writer = XMLWriter::new(&tempfile);
470
471 writer.xml_formula_element("1+2", 3.0, &attributes);
472
473 let got = read_xmlfile_data(&mut tempfile);
474 assert_eq!(got, expected);
475 }
476
477 #[test]
478 fn test_xml_si_element() {
479 let expected = r#"<si><t span="8">foo</t></si>"#;
480 let attributes = vec![("span", "8")];
481
482 let mut tempfile = tempfile().unwrap();
483 let mut writer = XMLWriter::new(&tempfile);
484
485 writer.xml_si_element("foo", &attributes);
486
487 let got = read_xmlfile_data(&mut tempfile);
488 assert_eq!(got, expected);
489 }
490
491 #[test]
492 fn test_xml_rich_si_element() {
493 let expected = r#"<si>foo</si>"#;
494
495 let mut tempfile = tempfile().unwrap();
496 let mut writer = XMLWriter::new(&tempfile);
497
498 writer.xml_rich_si_element("foo");
499
500 let got = read_xmlfile_data(&mut tempfile);
501 assert_eq!(got, expected);
502 }
503}