1use std::fmt::{self, Display, Formatter};
16use super::*;
17
18const INDENT: usize = 4;
19
20struct IndentedXml<'a>(&'a Xml, usize);
21struct IndentedTag<'a>(&'a Tag, usize);
22struct IndentedContent<'a>(&'a Content, usize);
23
24fn escape_attr(s: &str) -> String {
25 s.chars().fold(String::new(), |mut s, ch| {
26 match ch {
27 '\\' => s + "\\\\",
28 '\"' => s + "\\\"",
29 '\n' => s + "\\n",
30 _ => { s.push(ch); s },
31 }
32 })
33}
34
35impl Display for IndentedXml<'_> {
36 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
37 let Self(x, ind) = self;
38 let ind2 = ind + INDENT;
39 x.0.iter().try_for_each(|x| write!(f, "{}", IndentedContent(x, ind2)))
40 }
41}
42
43impl Display for IndentedTag<'_> {
44 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
45 let Self(tag, ind) = self;
46 let ind2 = ind + INDENT;
47 let n = &tag.name;
48 write!(f, "{:ind$}<{n}", "")?;
49 tag.attrs.iter().try_for_each(|a| write!(f, " {a}"))?;
50 if let Some(inner) = tag.inner.as_ref() {
51 match &inner.0[..] {
52 &[] => write!(f, "></{n}>"),
53 &[ref x] => {
54 let sep = match x {
55 Content::Tag(_) => true,
56 Content::Nested(_) => true,
57 Content::Word(_) => false,
58 };
59
60 if sep {
61 writeln!(f ,">")?;
62 writeln!(f, "{}", IndentedContent(x, ind2))?;
63 write!(f, "{:ind$}</{n}>", "")
64 } else {
65 write!(f, ">{x}</{n}>")
66 }
67 },
68 data => {
69 writeln!(f, ">")?;
70 data.iter().try_for_each(|x| writeln!(f, "{}", IndentedContent(x, ind2)))?;
71 write!(f, "{:ind$}</{n}>", "")
72 }
73 }
74 } else {
75 write!(f, " />")
76 }
77 }
78}
79
80impl Display for IndentedContent<'_> {
81 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
82 let Self(x, ind) = self;
83 match x {
84 Content::Tag(t) => write!(f, "{}", IndentedTag(t, *ind)),
85 Content::Word(w) => write!(f, "{:ind$}{}", "", w),
86 Content::Nested(x) => write!(f, "{}", IndentedXml(x, *ind - INDENT)),
87 }
88 }
89}
90
91
92impl Display for Document {
93 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
94 if self.xml_decl_attrs.len() > 0 {
95 write!(f, "<?xml")?;
96 for (n, v) in &self.xml_decl_attrs {
97 write!(f, " {}=\"{}\"", n, escape_attr(v))?;
98 }
99 writeln!(f, "?>")?;
100 }
101 if let Some(doctype) = &self.doctype {
102 writeln!(f, "<!DOCTYPE {doctype}>")?;
103 }
104 write!(f, "{}", self.root)
105 }
106}
107
108impl Display for Xml {
109 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
110 self.0.iter().try_for_each(|x| write!(f, "{x}"))
111 }
112}
113
114impl Display for Tag {
115 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
116 write!(f, "{}", IndentedTag(self, 0))
117 }
118}
119
120impl Display for Attr {
121 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
122 write!(f, "{}=\"{}\"", self.name, escape_attr(&self.value))
123 }
124}
125
126impl Display for Content {
127 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
128 match self {
129 Self::Tag(t) => write!(f, "{t}"),
130 Self::Word(w) => write!(f, "{w}"),
131 Self::Nested(x) => write!(f, "{}", IndentedXml(x, 0)),
132 }
133 }
134}
135