1use super::{Element, Name, Node};
12
13pub fn serialize(root: &Element) -> Vec<u8> {
15 let mut out = String::with_capacity(4096);
16 out.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
17 element(&mut out, root);
18 out.into_bytes()
19}
20
21fn element(out: &mut String, e: &Element) {
22 out.push('<');
23 name(out, &e.name);
24 for attr in &e.attrs {
25 out.push(' ');
26 name(out, &attr.name);
27 out.push_str("=\"");
28 escape_attribute(out, &attr.value);
29 out.push('"');
30 }
31 if e.children.is_empty() && e.self_closing {
32 out.push_str("/>");
33 return;
34 }
35 out.push('>');
36 for child in &e.children {
37 match child {
38 Node::Element(child) => element(out, child),
39 Node::Text(t) => escape_text(out, t),
40 Node::CData(t) => {
41 out.push_str("<![CDATA[");
42 out.push_str(t);
43 out.push_str("]]>");
44 }
45 Node::Comment(t) => {
46 out.push_str("<!--");
47 out.push_str(t);
48 out.push_str("-->");
49 }
50 Node::ProcessingInstruction(t) => {
51 out.push_str("<?");
52 out.push_str(t);
53 out.push_str("?>");
54 }
55 }
56 }
57 out.push_str("</");
58 name(out, &e.name);
59 out.push('>');
60}
61
62fn name(out: &mut String, n: &Name) {
63 if let Some(prefix) = &n.prefix {
64 out.push_str(prefix);
65 out.push(':');
66 }
67 out.push_str(&n.local);
68}
69
70fn escape_text(out: &mut String, text: &str) {
71 for c in text.chars() {
72 match c {
73 '&' => out.push_str("&"),
74 '<' => out.push_str("<"),
75 '>' => out.push_str(">"),
80 _ => out.push(c),
81 }
82 }
83}
84
85fn escape_attribute(out: &mut String, value: &str) {
86 for c in value.chars() {
87 match c {
88 '&' => out.push_str("&"),
89 '<' => out.push_str("<"),
90 '>' => out.push_str(">"),
91 '"' => out.push_str("""),
92 '\t' => out.push_str("	"),
98 '\n' => out.push_str(" "),
99 '\r' => out.push_str(" "),
100 _ => out.push(c),
101 }
102 }
103}