1pub mod element_builder;
2pub mod attribute_like;
3pub mod document;
4
5use std::fmt::{Display, Formatter};
6use crate::xml::attribute_like::AttributeLike;
7use crate::xml::element_builder::{ElementBuilder, Named};
8
9fn indent(what: impl AsRef<str>, with: impl AsRef<str>) -> String {
10 let what = what.as_ref();
11 let with = with.as_ref();
12 let indented_newline = format!("\n{}", with);
13 format!("{}{}", with, what.replace("\n", &indented_newline))
14}
15
16
17
18#[derive(Debug, Clone)]
19pub struct Element {
20 pub name: String,
21 pub attributes: Option<Vec<(String, String)>>,
22 pub children: Option<Vec<Element>>,
23 pub content: Option<String>
24}
25
26impl Element {
27 pub fn builder() -> ElementBuilder<element_builder::Unnamed> {
28 ElementBuilder::new()
29 }
30
31 pub fn has_content_or_children(&self) -> bool {
32 self.content.is_some() || self.children.is_some()
33 }
34
35 fn write_attributes(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
36 if let Some(attributes) = &self.attributes {
37 for attribute in attributes {
38 write!(f, " {}=\"{}\"", attribute.key(), attribute.value())?;
39 }
40 }
41
42 Ok(())
43 }
44
45 fn write_children_and_contents(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
46 if let Some(children) = &self.children {
47 for child in children {
48 write!(f, "\n{}", indent(child.to_string(), "\t"))?;
49 }
50 }
51
52 if let Some(content) = &self.content {
53 write!(f, "\n{}", indent(content, "\t"))?;
54 }
55
56 Ok(())
57 }
58
59 pub fn rebuild(self) -> ElementBuilder<Named> {
63 ElementBuilder::<Named> {
64 name: Named(self.name),
65 attributes: self.attributes.unwrap_or(Vec::new()),
66 children: self.children.unwrap_or(Vec::new()),
67 content: self.content,
68 }
69 }
70}
71
72impl Display for Element {
73 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
74 if self.has_content_or_children() {
75 write!(f, "<{}", self.name)?;
76 self.write_attributes(f)?;
77 write!(f, ">")?;
78 self.write_children_and_contents(f)?;
79 write!(f, "\n</{}>", self.name)
80 } else {
81 write!(f, "<{}", self.name)?;
82 self.write_attributes(f)?;
83 write!(f, "/>")
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn babys_first() {
94 let node = Element::builder()
95 .name("Baby".to_string())
96 .build();
97 assert_eq!(node.to_string(), "<Baby/>");
98 }
99
100 #[test]
101 fn babys_second() {
102 let node = Element::builder()
103 .name("Baby".to_string())
104 .with_attribute(("age", 4))
105 .build();
106 assert_eq!(node.to_string(), "<Baby age=\"4\"/>");
107 }
108
109 #[test]
110 fn babys_third() {
111 let node = Element::builder()
112 .name("Baby".to_string())
113 .with_attribute(("age", 4))
114 .with_child(Element::builder().name("child").build())
115 .build();
116 assert_eq!(node.to_string(), "<Baby age=\"4\">\n\t<child/>\n</Baby>");
117 }
118}