From 052c46635ac891d1292976853fac5d1fe0ef09c4 Mon Sep 17 00:00:00 2001 From: Astro Date: Sat, 12 Aug 2017 02:05:18 +0200 Subject: [PATCH] escape text and attribute values --- src/element.rs | 26 +++++++++++++++++++++++--- src/tests.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/element.rs b/src/element.rs index ee24850..db41fd5 100644 --- a/src/element.rs +++ b/src/element.rs @@ -18,6 +18,22 @@ use std::slice; use convert::{IntoElements, IntoAttributeValue, ElementEmitter}; +/// Escape XML text +pub fn write_escaped(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(&self, writer: &mut W, last_namespace: &mut Option) -> 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() { diff --git a/src/tests.rs b/src/tests.rs index bc71ca2..6dd6a2b 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -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#""# + ); +} + +#[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#"<3"# + ); +} + #[test] fn builder_works() { let elem = Element::builder("a")