From 5a783bcb9faff840a0806afe5b3d7cdaa4842929 Mon Sep 17 00:00:00 2001 From: Dobroslaw Kijowski Date: Wed, 15 Jan 2025 18:15:37 +0100 Subject: [PATCH 1/2] Add an option to skip line breaks --- src/builder.rs | 14 ++++++++++++++ src/xml.rs | 24 ++++++++++++++++++++---- src/xmlelement.rs | 32 ++++++++++++++++++++++++-------- tests/tests.rs | 19 +++++++++++++++++++ 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 5aa5a36..183e891 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -28,6 +28,11 @@ pub struct XMLBuilder { /// /// Defaults to `false`. sort_attributes: bool, + + /// Whether we want to break lines or not. + /// + /// Defaults to `true`. + break_lines: bool, } impl Default for XMLBuilder { @@ -38,6 +43,7 @@ impl Default for XMLBuilder { standalone: None, indent: true, sort_attributes: false, + break_lines: true, } } } @@ -91,6 +97,13 @@ impl XMLBuilder { self } + /// Sets whether to break lines. + pub fn break_lines(mut self, break_lines: bool) -> Self { + self.break_lines = break_lines; + + self + } + /// Builds a new XML structure by consuming self. pub fn build(self) -> XML { XML::new( @@ -99,6 +112,7 @@ impl XMLBuilder { self.standalone, self.indent, self.sort_attributes, + self.break_lines, ) } } diff --git a/src/xml.rs b/src/xml.rs index 748cf4c..0999de2 100644 --- a/src/xml.rs +++ b/src/xml.rs @@ -32,6 +32,11 @@ pub struct XML { /// Defaults to `true`. indent: bool, + /// Whether we want to break lines or not. + /// + /// Defaults to `true`. + break_lines: bool, + /// The root XML element. root: Option, } @@ -43,6 +48,7 @@ impl XML { standalone: Option, indent: bool, sort_attributes: bool, + break_lines: bool, ) -> Self { Self { version, @@ -50,6 +56,7 @@ impl XML { standalone, indent, sort_attributes, + break_lines, root: None, } } @@ -71,16 +78,25 @@ 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, + )?; } Ok(()) diff --git a/src/xmlelement.rs b/src/xmlelement.rs index 07ea42f..5613738 100644 --- a/src/xmlelement.rs +++ b/src/xmlelement.rs @@ -140,8 +140,9 @@ impl XMLElement { writer: &mut W, should_sort: bool, should_indent: bool, + should_break_lines: bool, ) -> Result<()> { - self.render_level(writer, 0, should_sort, should_indent) + self.render_level(writer, 0, should_sort, should_indent, should_break_lines) } /// Internal method rendering and indenting a XMLELement object @@ -156,30 +157,45 @@ impl XMLElement { level: usize, should_sort: bool, should_indent: bool, + should_break_lines: 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)?; + 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, + )?; } - 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..605188b 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -67,6 +67,25 @@ 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_xml_version_1_0() { let xml = XMLBuilder::new().version(XMLVersion::XML1_0).build(); From 20371e418b1f4b952fae13dfc0609ca0cc616da9 Mon Sep 17 00:00:00 2001 From: Dobroslaw Kijowski Date: Fri, 17 Jan 2025 13:33:27 +0100 Subject: [PATCH 2/2] Add an option to expand empty tags --- src/builder.rs | 14 ++++++++++++++ src/xml.rs | 8 ++++++++ src/xmlelement.rs | 35 +++++++++++++++++++++++++++-------- tests/tests.rs | 21 +++++++++++++++++++++ 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 183e891..a840701 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -33,6 +33,11 @@ pub struct XMLBuilder { /// /// 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 { @@ -44,6 +49,7 @@ impl Default for XMLBuilder { indent: true, sort_attributes: false, break_lines: true, + expand_empty_tags: false, } } } @@ -104,6 +110,13 @@ impl XMLBuilder { 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( @@ -113,6 +126,7 @@ impl XMLBuilder { self.indent, self.sort_attributes, self.break_lines, + self.expand_empty_tags, ) } } diff --git a/src/xml.rs b/src/xml.rs index 0999de2..b180413 100644 --- a/src/xml.rs +++ b/src/xml.rs @@ -37,6 +37,11 @@ pub struct XML { /// 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, } @@ -49,6 +54,7 @@ impl XML { indent: bool, sort_attributes: bool, break_lines: bool, + expand_empty_tags: bool, ) -> Self { Self { version, @@ -57,6 +63,7 @@ impl XML { indent, sort_attributes, break_lines, + expand_empty_tags, root: None, } } @@ -96,6 +103,7 @@ impl XML { self.sort_attributes, self.indent, self.break_lines, + self.expand_empty_tags, )?; } diff --git a/src/xmlelement.rs b/src/xmlelement.rs index 5613738..fd3c4c1 100644 --- a/src/xmlelement.rs +++ b/src/xmlelement.rs @@ -141,8 +141,16 @@ impl XMLElement { 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, should_break_lines) + self.render_level( + writer, + 0, + should_sort, + should_indent, + should_break_lines, + should_expand_empty_tags, + ) } /// Internal method rendering and indenting a XMLELement object @@ -158,6 +166,7 @@ impl XMLElement { 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), @@ -171,13 +180,22 @@ impl XMLElement { let attributes = self.attributes_as_string(should_sort); match &self.content { - XMLElementContent::Empty => { - write!( - writer, - "{}<{}{} />{}", - indent, self.name, attributes, suffix - )?; - } + 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) => { write!(writer, "{}<{}{}>{}", indent, self.name, attributes, suffix)?; for elem in elements { @@ -187,6 +205,7 @@ impl XMLElement { should_sort, should_indent, should_break_lines, + should_expand_empty_tags, )?; } write!(writer, "{}{}", indent, self.name, suffix)?; diff --git a/tests/tests.rs b/tests/tests.rs index 605188b..9c494e1 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -86,6 +86,27 @@ fn test_line_breaks() { 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();