Repository: tafia/quick-xml
Pull request #96 (2017-11-15 18:44:35)

Fix double escape


Patch:
diff --git a/src/events/mod.rs b/src/events/mod.rs
index dbc1028..324d20d 100644
--- a/src/events/mod.rs
+++ b/src/events/mod.rs
@@ -303,7 +303,7 @@ pub struct BytesText<'a> {
 }
 
 impl<'a> BytesText<'a> {
-    /// Creates a new `BytesEnd` borrowing a slice
+    /// Creates a new `BytesText` borrowing a slice
     #[inline]
     pub fn borrowed(content: &'a [u8]) -> BytesText<'a> {
         BytesText {
@@ -311,7 +311,7 @@ impl<'a> BytesText<'a> {
         }
     }
 
-    /// Creates a new `BytesEnd` owning its name
+    /// Creates a new `BytesText` owning its name
     #[inline]
     pub fn owned(content: Vec<u8>) -> BytesText<'static> {
         BytesText {
@@ -319,6 +319,15 @@ impl<'a> BytesText<'a> {
         }
     }
 
+    /// Creates a new `BytesText` from text
+    #[inline]
+    pub fn from_str<S: AsRef<str>>(text: S) -> BytesText<'static> {
+        let bytes = escape(text.as_ref().as_bytes()).into_owned();
+        BytesText {
+            content: Cow::Owned(bytes),
+        }
+    }
+
     /// gets escaped content
     ///
     /// Searches for '&' into content and try to escape the coded character if possible
@@ -340,8 +349,8 @@ impl<'a> BytesText<'a> {
     /// Gets escaped content
     ///
     /// Searches for any of `<, >, &, ', "` and xml escapes them.
-    pub fn escaped(&self) -> Cow<[u8]> {
-        escape(self)
+    pub fn escaped(&self) -> &[u8] {
+        self.content.as_ref()
     }
 }
 


Test patch:
diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs
index b40f6f3..5f42422 100644
--- a/tests/unit_tests.rs
+++ b/tests/unit_tests.rs
@@ -596,6 +596,33 @@ fn test_read_write_roundtrip_results_in_identity() {
     assert_eq!(result, input.as_bytes());
 }
 
+#[test]
+fn test_read_write_roundtrip() {
+    let input = r#"
+        <?xml version="1.0" encoding="UTF-8"?>
+        <section ns:label="header">
+            <section ns:label="empty element section" />
+            <section ns:label="start/end section"></section>
+            <section ns:label="with text">data &lt;escaped&gt;</section>
+            </section>
+    "#;
+
+    let mut reader = Reader::from_str(input);
+    reader.trim_text(false).expand_empty_elements(false);
+    let mut writer = Writer::new(Cursor::new(Vec::new()));
+    let mut buf = Vec::new();
+    loop {
+        match reader.read_event(&mut buf) {
+            Ok(Eof) => break,
+            Ok(e) => assert!(writer.write_event(e).is_ok()),
+            Err(e) => panic!(e),
+        }
+    }
+
+    let result = writer.into_inner().into_inner();
+    assert_eq!(String::from_utf8(result).unwrap(), input.to_string());
+}
+
 #[test]
 fn test_read_write_roundtrip_escape() {
     let input = r#"
@@ -615,10 +642,45 @@ fn test_read_write_roundtrip_escape() {
         match reader.read_event(&mut buf) {
             Ok(Eof) => break,
             Ok(Text(e)) => {
-                let t = e.unescaped().unwrap();
+                let t = e.escaped();
+                assert!(
+                    writer
+                        .write_event(Event::Text(BytesText::owned(t.to_vec())))
+                        .is_ok()
+                );
+            }
+            Ok(e) => assert!(writer.write_event(e).is_ok()),
+            Err(e) => panic!(e),
+        }
+    }
+
+    let result = writer.into_inner().into_inner();
+    assert_eq!(String::from_utf8(result).unwrap(), input.to_string());
+}
+
+#[test]
+fn test_read_write_roundtrip_escape_text() {
+    let input = r#"
+        <?xml version="1.0" encoding="UTF-8"?>
+        <section ns:label="header">
+            <section ns:label="empty element section" />
+            <section ns:label="start/end section"></section>
+            <section ns:label="with text">data &lt;escaped&gt;</section>
+            </section>
+    "#;
+
+    let mut reader = Reader::from_str(input);
+    reader.trim_text(false).expand_empty_elements(false);
+    let mut writer = Writer::new(Cursor::new(Vec::new()));
+    let mut buf = Vec::new();
+    loop {
+        match reader.read_event(&mut buf) {
+            Ok(Eof) => break,
+            Ok(Text(e)) => {
+                let t = e.unescape_and_decode(&reader).unwrap();
                 assert!(
                     writer
-                        .write_event(Event::Text(BytesText::borrowed(&t)))
+                        .write_event(Event::Text(BytesText::from_str(t)))
                         .is_ok()
                 );
             }