diff --git a/src/builder.rs b/src/builder.rs index 5aa5a36..a840701 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -28,6 +28,16 @@ pub struct XMLBuilder { /// /// Defaults to `false`. sort_attributes: bool, + + /// Whether we want to break lines or not. + /// + /// Defaults to `true`. + break_lines: bool, + + /// Whether we want to expand empty tags or not. + /// + /// Defaults to `false`. + expand_empty_tags: bool, } impl Default for XMLBuilder { @@ -38,6 +48,8 @@ impl Default for XMLBuilder { standalone: None, indent: true, sort_attributes: false, + break_lines: true, + expand_empty_tags: false, } } } @@ -91,6 +103,20 @@ impl XMLBuilder { self } + /// Sets whether to break lines. + pub fn break_lines(mut self, break_lines: bool) -> Self { + self.break_lines = break_lines; + + self + } + + /// Sets whether to expand empty tags. + pub fn expand_empty_tags(mut self, expand_empty_tags: bool) -> Self { + self.expand_empty_tags = expand_empty_tags; + + self + } + /// Builds a new XML structure by consuming self. pub fn build(self) -> XML { XML::new( @@ -99,6 +125,8 @@ impl XMLBuilder { self.standalone, self.indent, self.sort_attributes, + self.break_lines, + self.expand_empty_tags, ) } } diff --git a/src/xml.rs b/src/xml.rs index 748cf4c..b180413 100644 --- a/src/xml.rs +++ b/src/xml.rs @@ -32,6 +32,16 @@ pub struct XML { /// Defaults to `true`. indent: bool, + /// Whether we want to break lines or not. + /// + /// Defaults to `true`. + break_lines: bool, + + /// Whether we want to expand empty tags or not. + /// + /// Defaults to `false`. + expand_empty_tags: bool, + /// The root XML element. root: Option, } @@ -43,6 +53,8 @@ impl XML { standalone: Option, indent: bool, sort_attributes: bool, + break_lines: bool, + expand_empty_tags: bool, ) -> Self { Self { version, @@ -50,6 +62,8 @@ impl XML { standalone, indent, sort_attributes, + break_lines, + expand_empty_tags, root: None, } } @@ -71,16 +85,26 @@ impl XML { Some(_) => r#" standalone="yes""#.to_string(), None => String::default(), }; + let suffix = match self.break_lines { + true => "\n", + false => "", + }; - writeln!( + write!( writer, - r#""#, - self.version, self.encoding, standalone_attribute + r#"{}"#, + self.version, self.encoding, standalone_attribute, suffix )?; // And then XML elements if present... if let Some(elem) = &self.root { - elem.render(&mut writer, self.sort_attributes, self.indent)?; + elem.render( + &mut writer, + self.sort_attributes, + self.indent, + self.break_lines, + self.expand_empty_tags, + )?; } Ok(()) diff --git a/src/xmlelement.rs b/src/xmlelement.rs index 07ea42f..fd3c4c1 100644 --- a/src/xmlelement.rs +++ b/src/xmlelement.rs @@ -140,8 +140,17 @@ impl XMLElement { writer: &mut W, should_sort: bool, should_indent: bool, + should_break_lines: bool, + should_expand_empty_tags: bool, ) -> Result<()> { - self.render_level(writer, 0, should_sort, should_indent) + self.render_level( + writer, + 0, + should_sort, + should_indent, + should_break_lines, + should_expand_empty_tags, + ) } /// Internal method rendering and indenting a XMLELement object @@ -156,30 +165,56 @@ impl XMLElement { level: usize, should_sort: bool, should_indent: bool, + should_break_lines: bool, + should_expand_empty_tags: bool, ) -> Result<()> { let indent = match should_indent { true => "\t".repeat(level), false => "".into(), }; + let suffix = match should_break_lines { + true => "\n", + false => "", + }; let attributes = self.attributes_as_string(should_sort); match &self.content { - XMLElementContent::Empty => { - writeln!(writer, "{}<{}{} />", indent, self.name, attributes)?; - } + XMLElementContent::Empty => match should_expand_empty_tags { + true => { + write!( + writer, + "{}<{}{}>{}", + indent, self.name, attributes, self.name, suffix + )?; + } + false => { + write!( + writer, + "{}<{}{} />{}", + indent, self.name, attributes, suffix + )?; + } + }, XMLElementContent::Elements(elements) => { - writeln!(writer, "{}<{}{}>", indent, self.name, attributes)?; + write!(writer, "{}<{}{}>{}", indent, self.name, attributes, suffix)?; for elem in elements { - elem.render_level(writer, level + 1, should_sort, should_indent)?; + elem.render_level( + writer, + level + 1, + should_sort, + should_indent, + should_break_lines, + should_expand_empty_tags, + )?; } - writeln!(writer, "{}", indent, self.name)?; + write!(writer, "{}{}", indent, self.name, suffix)?; } XMLElementContent::Text(text) => { - writeln!( + write!( writer, - "{}<{}{}>{}", - indent, self.name, attributes, text, self.name + "{}<{}{}>{}{}", + indent, self.name, attributes, text, self.name, suffix )?; } }; diff --git a/tests/tests.rs b/tests/tests.rs index 9d06b4c..9c494e1 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -67,6 +67,46 @@ fn test_indent() { assert_eq!(res, expected, "Both values does not match..."); } +#[test] +fn test_line_breaks() { + let mut xml = XMLBuilder::new().break_lines(false).build(); + + let mut root = XMLElement::new("root"); + let element = XMLElement::new("element"); + + root.add_child(element).unwrap(); + xml.set_root_element(root); + + let mut writer: Vec = Vec::new(); + xml.generate(&mut writer).unwrap(); + + let expected = "\t"; + let res = std::str::from_utf8(&writer).unwrap(); + + assert_eq!(res, expected, "Both values does not match..."); +} + +#[test] +fn test_expand_empty_tags() { + let mut xml = XMLBuilder::new().expand_empty_tags(true).build(); + + let mut root = XMLElement::new("root"); + let element = XMLElement::new("element"); + + root.add_child(element).unwrap(); + + xml.set_root_element(root); + + let mut writer: Vec = Vec::new(); + xml.generate(&mut writer).unwrap(); + + let expected = + "\n\n\t\n\n"; + let res = std::str::from_utf8(&writer).unwrap(); + + assert_eq!(res, expected, "Both values does not match..."); +} + #[test] fn test_xml_version_1_0() { let xml = XMLBuilder::new().version(XMLVersion::XML1_0).build();