diff --git a/Changelog.md b/Changelog.md index 91dee4f6..3756ca31 100644 --- a/Changelog.md +++ b/Changelog.md @@ -25,6 +25,8 @@ - [#395]: Add support for XML Schema `xs:list` - [#324]: `Reader::from_str` / `Deserializer::from_str` / `from_str` now ignore the XML declared encoding and always use UTF-8 +- [#413]: Added `Attribute::from_bytes()`, `Attribute::from_escaped_bytes()`, + `Attribute::from_str()` and `Attribute::from_escaped_str()` constructors. ### Bug Fixes @@ -40,6 +42,9 @@ - [#363]: Do not generate empty `Event::Text` events - [#412]: Fix using incorrect encoding if `read_to_end` family of methods or `read_text` method not found a corresponding end tag and reader has non-UTF-8 encoding +- [#413]: `Attribute::from((&[u8], &[u8]))` was made consistent with `Attribute::from((&str, &str))` + in that both will now escape the value. WARNING: if you were passing escaped values via this + approach before, your values will be double-escaped and incorrect. ### Misc Changes @@ -131,6 +136,7 @@ [#403]: https://github.com/tafia/quick-xml/pull/403 [#407]: https://github.com/tafia/quick-xml/pull/407 [#412]: https://github.com/tafia/quick-xml/pull/412 +[#413]: https://github.com/tafia/quick-xml/pull/413 ## 0.23.0 -- 2022-05-08 diff --git a/src/events/attributes.rs b/src/events/attributes.rs index 51f1455c..11c3fad1 100644 --- a/src/events/attributes.rs +++ b/src/events/attributes.rs @@ -32,6 +32,82 @@ pub struct Attribute<'a> { } impl<'a> Attribute<'a> { + /// Creates new attribute from text representation. + /// Key is stored as-is, but the value will be escaped. + /// + /// # Examples + /// + /// ``` + /// # use pretty_assertions::assert_eq; + /// use quick_xml::events::attributes::Attribute; + /// + /// let features = Attribute::from_str("features", "Bells & whistles"); + /// assert_eq!(features.value, "Bells & whistles".as_bytes()); + /// ``` + pub fn from_str(key: &'a str, val: &'a str) -> Attribute<'a> { + Attribute { + key: QName(key.as_bytes()), + value: escape(val.as_bytes()), + } + } + + /// Creates new attribute from text representation. + /// Does not apply any transformation to either key or value. + /// + /// # Examples + /// + /// ``` + /// # use pretty_assertions::assert_eq; + /// use quick_xml::events::attributes::Attribute; + /// + /// let features = Attribute::from_escaped_str("features", "Bells & whistles"); + /// assert_eq!(features.value, "Bells & whistles".as_bytes()); + /// ``` + pub fn from_escaped_str(key: &'a str, val: &'a str) -> Attribute<'a> { + Attribute { + key: QName(key.as_bytes()), + value: Cow::from(val.as_bytes()), + } + } + + /// Creates new attribute from raw bytes. + /// Key is stored as-is, but the value will be escaped. + /// + /// # Examples + /// + /// ``` + /// # use pretty_assertions::assert_eq; + /// use quick_xml::events::attributes::Attribute; + /// + /// let features = Attribute::from_bytes("features".as_bytes(), "Bells & whistles".as_bytes()); + /// assert_eq!(features.value, "Bells & whistles".as_bytes()); + /// ``` + pub fn from_bytes(key: &'a [u8], val: &'a [u8]) -> Attribute<'a> { + Attribute { + key: QName(key), + value: escape(val), + } + } + + /// Creates new attribute from raw bytes. + /// Does not apply any transformation to either key or value. + /// + /// # Examples + /// + /// ``` + /// # use pretty_assertions::assert_eq; + /// use quick_xml::events::attributes::Attribute; + /// + /// let features = Attribute::from_escaped_bytes("features".as_bytes(), "Bells & whistles".as_bytes()); + /// assert_eq!(features.value, "Bells & whistles".as_bytes()); + /// ``` + pub fn from_escaped_bytes(key: &'a [u8], val: &'a [u8]) -> Attribute<'a> { + Attribute { + key: QName(key), + value: Cow::from(val), + } + } + /// Returns the unescaped value. /// /// This is normally the value you are interested in. Escape sequences such as `>` are @@ -132,7 +208,7 @@ impl<'a> Debug for Attribute<'a> { impl<'a> From<(&'a [u8], &'a [u8])> for Attribute<'a> { /// Creates new attribute from raw bytes. - /// Does not apply any transformation to both key and value. + /// Key is stored as-is, but the value will be escaped. /// /// # Examples /// @@ -140,14 +216,11 @@ impl<'a> From<(&'a [u8], &'a [u8])> for Attribute<'a> { /// # use pretty_assertions::assert_eq; /// use quick_xml::events::attributes::Attribute; /// - /// let features = Attribute::from(("features".as_bytes(), "Bells & whistles".as_bytes())); + /// let features = Attribute::from(("features".as_bytes(), "Bells & whistles".as_bytes())); /// assert_eq!(features.value, "Bells & whistles".as_bytes()); /// ``` fn from(val: (&'a [u8], &'a [u8])) -> Attribute<'a> { - Attribute { - key: QName(val.0), - value: Cow::from(val.1), - } + Attribute::from_bytes(val.0, val.1) } } @@ -165,10 +238,7 @@ impl<'a> From<(&'a str, &'a str)> for Attribute<'a> { /// assert_eq!(features.value, "Bells & whistles".as_bytes()); /// ``` fn from(val: (&'a str, &'a str)) -> Attribute<'a> { - Attribute { - key: QName(val.0.as_bytes()), - value: escape(val.1.as_bytes()), - } + Attribute::from_str(val.0, val.1) } }