Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/xmlcontent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ pub enum XMLElementContent {
Empty,

/// The content is a list of XML elements.
Elements(Vec<XMLElement>),
Mixed(Vec<XMLElementContent>),

/// The content is an XML element.
/// Needs to be boxed to avoid infinite size.
Element(Box<XMLElement>),

/// The content is a textual string.
Text(String),
Expand Down
97 changes: 67 additions & 30 deletions src/xmlelement.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::Write;

use crate::{Result, XMLElementContent, XMLError, escape_str};
use crate::{Result, XMLElementContent, escape_str};

/// Structure representing an XML element field.
#[derive(Clone)]
Expand Down Expand Up @@ -58,23 +58,28 @@ impl XMLElement {

/// Adds a new `XMLElement` child object to the references `XMLElement`.
///
/// Raises `XMLError` if trying to add a child to a text `XMLElement`.
///
/// # Arguments
///
/// * `element` - A `XMLElement` object to add as child
pub fn add_child(&mut self, element: Self) -> Result<()> {
match self.content {
XMLElementContent::Empty => {
self.content = XMLElementContent::Elements(vec![element]);
self.content = XMLElementContent::Element(Box::new(element))
}
XMLElementContent::Text(ref s) => {
self.content = XMLElementContent::Mixed(vec![
XMLElementContent::Text(s.clone()),
XMLElementContent::Element(Box::new(element)),
]);
}
XMLElementContent::Elements(ref mut e) => {
e.push(element);
XMLElementContent::Element(ref b) => {
self.content = XMLElementContent::Mixed(vec![
XMLElementContent::Element(b.clone()),
XMLElementContent::Element(Box::new(element)),
]);
}
XMLElementContent::Text(_) => {
return Err(XMLError::InsertError(
"Cannot insert child inside an element with text".into(),
));
XMLElementContent::Mixed(ref mut v) => {
v.push(XMLElementContent::Element(Box::new(element)));
}
}

Expand All @@ -90,13 +95,21 @@ impl XMLElement {
/// * `text` - A string containing the text to add to the object
pub fn add_text(&mut self, text: String) -> Result<()> {
match self.content {
XMLElementContent::Empty => {
self.content = XMLElementContent::Text(text);
XMLElementContent::Empty => self.content = XMLElementContent::Text(text),
XMLElementContent::Text(ref s) => {
self.content = XMLElementContent::Mixed(vec![
XMLElementContent::Text(s.clone()),
XMLElementContent::Text(text),
]);
}
XMLElementContent::Element(ref b) => {
self.content = XMLElementContent::Mixed(vec![
XMLElementContent::Element(b.clone()),
XMLElementContent::Text(text),
]);
}
_ => {
return Err(XMLError::InsertError(
"Cannot insert text in a non-empty element".into(),
));
XMLElementContent::Mixed(ref mut v) => {
v.push(XMLElementContent::Text(text));
}
}

Expand Down Expand Up @@ -194,29 +207,53 @@ impl XMLElement {
indent, self.name, attributes, suffix
)?;
}
}
XMLElementContent::Elements(elements) => {
},
XMLElementContent::Element(element) => {
write!(writer, "{}<{}{}>{}", indent, self.name, attributes, suffix)?;
for elem in elements {
elem.render_level(
writer,
level + 1,
should_sort,
should_indent,
should_break_lines,
should_expand_empty_tags,
)?;
}
element.render_level(
writer,
level + 1,
should_sort,
should_indent,
should_break_lines,
should_expand_empty_tags)?;
write!(writer, "{}</{}>{}", indent, self.name, suffix)?;
}
},
XMLElementContent::Text(text) => {
write!(
writer,
"{}<{}{}>{}</{}>{}",
indent, self.name, attributes, text, self.name, suffix
)?;
},
XMLElementContent::Mixed(children) => {
let higher_indent = "\t".to_string() + &indent;
write!(writer, "{}<{}{}>{}", indent, self.name, attributes, suffix)?;
for content in children {
match content {
// Should be unreachable
XMLElementContent::Empty => {},
// Should be unreachable
XMLElementContent::Mixed(_) => {},

XMLElementContent::Element(element) => {
element.render_level(
writer,
level + 1,
should_sort,
should_indent,
should_break_lines,
should_expand_empty_tags,
)?;
}
XMLElementContent::Text(text) => {
write!(writer, "{}{}{}", higher_indent, text, suffix)?;
}
};
}
write!(writer, "{}</{}>{}", indent, self.name, suffix)?;
}
}
};

Ok(())
}
Expand Down
26 changes: 19 additions & 7 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,19 +133,31 @@ fn test_xml_version_1_1() {
}

#[test]
#[should_panic(expected = "Cannot insert child inside an element with text")]
fn test_panic_child_for_text_element() {
let xml = XMLBuilder::new().build();
fn test_complex_mixed_children() {
let mut xml = XMLBuilder::new().build();

let mut xml_child = XMLElement::new("panic");
let mut xml_child = XMLElement::new("mixed");
xml_child
.add_text("This should panic right after this...".into())
.add_text("Let's start with a text".into())
.unwrap();
xml_child.add_attribute("complexity", "much");

let xml_child2 = XMLElement::new("sorry");
let xml_child2 = XMLElement::new("element_then");
xml_child.add_child(xml_child2).unwrap();

xml.generate(std::io::stdout()).unwrap();
xml.set_root_element(xml_child);

let mut writer: Vec<u8> = Vec::new();
xml.generate(&mut writer).unwrap();

let expected = "<?xml version=\"1.0\"?>
<mixed complexity=\"much\">
\tLet's start with a text
\t<element_then />
</mixed>\n";
let res = std::str::from_utf8(&writer).unwrap();

assert_eq!(res, expected, "Both values does not match...")
}

#[test]
Expand Down
Loading