recurve_svg/xml/
mod.rs

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    /// Used to convert an existing XML element back to it's builder...This is a workaround to the 
60    /// workaround to the workaround. Someone really ought to come up with a less drain bramaged way
61    /// to do this.
62    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}