@@ -18,6 +18,22 @@ use std::slice;
use convert::{IntoElements, IntoAttributeValue, ElementEmitter};
+/// Escape XML text
+pub fn write_escaped<W: Write>(writer: &mut W, input: &str) -> Result<()> {
+ for c in input.chars() {
+ match c {
+ '&' => write!(writer, "&")?,
+ '<' => write!(writer, "<")?,
+ '>' => write!(writer, ">")?,
+ '\'' => write!(writer, "'")?,
+ '"' => write!(writer, """)?,
+ _ => write!(writer, "{}", c)?,
+ }
+ }
+
+ Ok(())
+}
+
/// A node in an element tree.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Node {
@@ -71,7 +87,7 @@ impl Node {
fn write_to_inner<W: Write>(&self, writer: &mut W, last_namespace: &mut Option<String>) -> Result<()>{
match *self {
Node::Element(ref elmt) => elmt.write_to_inner(writer, last_namespace)?,
- Node::Text(ref s) => write!(writer, "{}", s)?,
+ Node::Text(ref s) => write_escaped(writer, s)?,
}
Ok(())
@@ -323,13 +339,17 @@ impl Element {
if let Some(ref ns) = self.namespace {
if *last_namespace != self.namespace {
- write!(writer, " xmlns=\"{}\"", ns)?;
+ write!(writer, " xmlns=\"")?;
+ write_escaped(writer, ns)?;
+ write!(writer, "\"")?;
*last_namespace = Some(ns.clone());
}
}
for (key, value) in &self.attributes {
- write!(writer, " {}=\"{}\"", key, value)?;
+ write!(writer, " {}=\"", key)?;
+ write_escaped(writer, value)?;
+ write!(writer, "\"")?;
}
if self.children.is_empty() {
@@ -43,6 +43,34 @@ fn writer_works() {
assert_eq!(String::from_utf8(writer).unwrap(), TEST_STRING);
}
+#[test]
+fn writer_escapes_attributes() {
+ let root = Element::builder("root")
+ .attr("a", "\"Air\" quotes")
+ .build();
+ let mut writer = Vec::new();
+ {
+ root.write_to(&mut writer).unwrap();
+ }
+ assert_eq!(String::from_utf8(writer).unwrap(),
+ r#"<?xml version="1.0" encoding="utf-8"?><root a=""Air" quotes" />"#
+ );
+}
+
+#[test]
+fn writer_escapes_text() {
+ let root = Element::builder("root")
+ .append("<3")
+ .build();
+ let mut writer = Vec::new();
+ {
+ root.write_to(&mut writer).unwrap();
+ }
+ assert_eq!(String::from_utf8(writer).unwrap(),
+ r#"<?xml version="1.0" encoding="utf-8"?><root><3</root>"#
+ );
+}
+
#[test]
fn builder_works() {
let elem = Element::builder("a")