//! XML escaping. /// Escape text for an element's content. pub fn text(value: &str) -> String { let mut out = String::with_capacity(value.len()); for ch in value.chars() { match ch { '&' => out.push_str("&"), '<' => out.push_str("<"), '>' => out.push_str(">"), _ => out.push(ch), } } out } /// Escape text for an attribute value, which is always double-quoted here. pub fn attr(value: &str) -> String { let mut out = String::with_capacity(value.len()); for ch in value.chars() { match ch { '&' => out.push_str("&"), '<' => out.push_str("<"), '>' => out.push_str(">"), '"' => out.push_str("""), _ => out.push(ch), } } out } #[cfg(test)] mod tests { use super::*; #[test] fn escapes_markup_characters() { assert_eq!(text("a & b < c > d"), "a & b < c > d"); // A quote is only significant inside an attribute, so content keeps it. assert_eq!(text("say \"hi\""), "say \"hi\""); assert_eq!(attr("say \"hi\" & bye"), "say "hi" & bye"); } #[test] fn leaves_ordinary_text_alone() { assert_eq!(text("plain text 123"), "plain text 123"); } }