Merge branch 'escaping' into 'master'
escape text and attribute values See merge request !15
This commit is contained in:
commit
db3c4e43e3
2 changed files with 51 additions and 3 deletions
|
@ -18,6 +18,22 @@ use std::slice;
|
||||||
|
|
||||||
use convert::{IntoElements, IntoAttributeValue, ElementEmitter};
|
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.
|
/// A node in an element tree.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Node {
|
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<()>{
|
fn write_to_inner<W: Write>(&self, writer: &mut W, last_namespace: &mut Option<String>) -> Result<()>{
|
||||||
match *self {
|
match *self {
|
||||||
Node::Element(ref elmt) => elmt.write_to_inner(writer, last_namespace)?,
|
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(())
|
Ok(())
|
||||||
|
@ -323,13 +339,17 @@ impl Element {
|
||||||
|
|
||||||
if let Some(ref ns) = self.namespace {
|
if let Some(ref ns) = self.namespace {
|
||||||
if *last_namespace != 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());
|
*last_namespace = Some(ns.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, value) in &self.attributes {
|
for (key, value) in &self.attributes {
|
||||||
write!(writer, " {}=\"{}\"", key, value)?;
|
write!(writer, " {}=\"", key)?;
|
||||||
|
write_escaped(writer, value)?;
|
||||||
|
write!(writer, "\"")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.children.is_empty() {
|
if self.children.is_empty() {
|
||||||
|
|
28
src/tests.rs
28
src/tests.rs
|
@ -43,6 +43,34 @@ fn writer_works() {
|
||||||
assert_eq!(String::from_utf8(writer).unwrap(), TEST_STRING);
|
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]
|
#[test]
|
||||||
fn builder_works() {
|
fn builder_works() {
|
||||||
let elem = Element::builder("a")
|
let elem = Element::builder("a")
|
||||||
|
|
Loading…
Reference in a new issue