From d2bcd50b7f447a99546db1e4fa4ffe038e0e6c2f Mon Sep 17 00:00:00 2001 From: Andrey Kutejko Date: Tue, 27 Dec 2022 11:11:26 +0100 Subject: [PATCH] Upgrade quick-xml to 0.27 --- .github/workflows/build.yml | 2 +- CHANGELOG.md | 3 +- Cargo.toml | 4 +- src/category.rs | 29 +++++----- src/content.rs | 51 +++++++++-------- src/entry.rs | 55 +++++++++--------- src/extension/mod.rs | 7 +-- src/extension/util.rs | 81 ++++++++++++++++---------- src/feed.rs | 110 ++++++++++++++++++++++-------------- src/generator.rs | 24 ++++---- src/link.rs | 30 ++++++---- src/person.rs | 31 +++++----- src/source.rs | 55 +++++++++--------- src/text.rs | 31 +++++----- src/toxml.rs | 63 +++++---------------- src/util.rs | 92 ++++++++++++++++++++++++------ 16 files changed, 381 insertions(+), 287 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 091e084..bbb4b8b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: - nightly - beta - stable - - 1.42.0 + - 1.52.0 steps: - uses: actions/checkout@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6678de6..2a09ea3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ - Wrap `quick_xml::XmlError` into a newtype [`#65`](https://github.com/rust-syndication/atom/pull/65) - Implement `std::error::Error` for `XmlError`. Mark helper traits as `pub(crate)` to prevent their accidental leakage to public API [`#66`](https://github.com/rust-syndication/atom/pull/66) -- Bump MSRV (Minimum Supported Rust Version) from 1.40.0 to 1.42.0 [`#66`](https://github.com/rust-syndication/atom/pull/66) +- Bump MSRV (Minimum Supported Rust Version) from 1.40.0 to 1.52.0 [`#66`](https://github.com/rust-syndication/atom/pull/66) and [`#67`](https://github.com/rust-syndication/atom/pull/67) +- Upgrade `quick_xml` to `0.27` [`#67`](https://github.com/rust-syndication/atom/pull/67) ## 0.11.0 - 2021-10-20 diff --git a/Cargo.toml b/Cargo.toml index be208f3..ad151fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,8 +13,8 @@ categories = ["parser-implementations"] include = ["src/*", "Cargo.toml", "LICENSE-MIT", "LICENSE-APACHE", "README.md"] [dependencies] -quick-xml = { version = "0.22", features = ["encoding"] } -derive_builder = { version = "0.10.2", optional = true } +quick-xml = { version = "0.27", features = ["encoding"] } +derive_builder = { version = "0.12", optional = true } never = { version = "0.1", optional = true } serde = { version = "1.0", optional = true, features = ["derive"] } chrono = { version = "0.4", default-features = false, features = ["alloc"] } diff --git a/src/category.rs b/src/category.rs index df23998..ebf4605 100644 --- a/src/category.rs +++ b/src/category.rs @@ -2,6 +2,7 @@ use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesStart, Event}; +use quick_xml::name::QName; use quick_xml::Reader; use quick_xml::Writer; @@ -138,29 +139,32 @@ impl FromXml for Category { for att in atts.with_checks(false).flatten() { match att.key { - b"term" => { + QName(b"term") => { category.term = att - .unescape_and_decode_value(reader) + .decode_and_unescape_value(reader) .map_err(XmlError::new)? + .to_string(); } - b"scheme" => { + QName(b"scheme") => { category.scheme = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), + ); } - b"label" => { + QName(b"label") => { category.label = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), + ); } _ => {} } } reader - .read_to_end(b"category", &mut Vec::new()) + .read_to_end_into(QName(b"category"), &mut Vec::new()) .map_err(XmlError::new)?; Ok(category) @@ -169,8 +173,7 @@ impl FromXml for Category { impl ToXml for Category { fn to_xml(&self, writer: &mut Writer) -> Result<(), XmlError> { - let name = b"category"; - let mut element = BytesStart::borrowed(name, name.len()); + let mut element = BytesStart::new("category"); element.push_attribute(("term", &*self.term)); if let Some(ref scheme) = self.scheme { diff --git a/src/content.rs b/src/content.rs index 7d7480d..280b996 100644 --- a/src/content.rs +++ b/src/content.rs @@ -2,6 +2,7 @@ use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; +use quick_xml::name::QName; use quick_xml::Reader; use quick_xml::Writer; @@ -174,29 +175,33 @@ impl FromXml for Content { for att in atts.with_checks(false).flatten() { match att.key { - b"xml:base" => { + QName(b"xml:base") => { content.base = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), + ); } - b"xml:lang" => { + QName(b"xml:lang") => { content.lang = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), + ); } - b"type" => { + QName(b"type") => { content.content_type = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), + ); } - b"src" => { + QName(b"src") => { content.src = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), + ); } _ => {} } @@ -213,8 +218,8 @@ impl FromXml for Content { impl ToXml for Content { fn to_xml(&self, writer: &mut Writer) -> Result<(), XmlError> { - let name = b"content"; - let mut element = BytesStart::borrowed(name, name.len()); + let name = "content"; + let mut element = BytesStart::new(name); if let Some(ref base) = self.base { element.push_attribute(("xml:base", base.as_str())); @@ -244,16 +249,16 @@ impl ToXml for Content { writer .write_event(Event::Text( if self.content_type.as_deref() == Some("xhtml") { - BytesText::from_escaped(value.as_bytes()) + BytesText::from_escaped(value) } else { - BytesText::from_plain(value.as_bytes()) + BytesText::new(value) }, )) .map_err(XmlError::new)?; } writer - .write_event(Event::End(BytesEnd::borrowed(name))) + .write_event(Event::End(BytesEnd::new(name))) .map_err(XmlError::new)?; Ok(()) @@ -293,9 +298,9 @@ mod test { loop { let mut buf = Vec::new(); - match reader.read_event(&mut buf).map_err(XmlError::new)? { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { Event::Start(element) => { - if element.name() == b"content" { + if element.name() == QName(b"content") { let content = Content::from_xml(&mut reader, element.attributes())?; return Ok(content); } else { diff --git a/src/entry.rs b/src/entry.rs index 05dbc5c..63b8732 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -2,13 +2,14 @@ use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesEnd, BytesStart, Event}; +use quick_xml::name::QName; use quick_xml::Reader; use quick_xml::Writer; use crate::category::Category; use crate::content::Content; use crate::error::{Error, XmlError}; -use crate::extension::util::{extension_name, parse_extension}; +use crate::extension::util::parse_extension; use crate::extension::ExtensionMap; use crate::fromxml::FromXml; use crate::link::Link; @@ -512,49 +513,51 @@ impl FromXml for Entry { let mut buf = Vec::new(); loop { - match reader.read_event(&mut buf).map_err(XmlError::new)? { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { Event::Start(element) => match element.name() { - b"id" => entry.id = atom_text(reader)?.unwrap_or_default(), - b"title" => entry.title = Text::from_xml(reader, element.attributes())?, - b"updated" => { + QName(b"id") => entry.id = atom_text(reader)?.unwrap_or_default(), + QName(b"title") => entry.title = Text::from_xml(reader, element.attributes())?, + QName(b"updated") => { entry.updated = atom_datetime(reader)?.unwrap_or_else(default_fixed_datetime) } - b"author" => entry + QName(b"author") => entry .authors .push(Person::from_xml(reader, element.attributes())?), - b"category" => entry + QName(b"category") => entry .categories .push(Category::from_xml(reader, element.attributes())?), - b"contributor" => entry + QName(b"contributor") => entry .contributors .push(Person::from_xml(reader, element.attributes())?), - b"link" => entry + QName(b"link") => entry .links .push(Link::from_xml(reader, element.attributes())?), - b"published" => entry.published = atom_datetime(reader)?, - b"rights" => entry.rights = Some(Text::from_xml(reader, element.attributes())?), - b"source" => { + QName(b"published") => entry.published = atom_datetime(reader)?, + QName(b"rights") => { + entry.rights = Some(Text::from_xml(reader, element.attributes())?) + } + QName(b"source") => { entry.source = Some(Source::from_xml(reader, element.attributes())?) } - b"summary" => { + QName(b"summary") => { entry.summary = Some(Text::from_xml(reader, element.attributes())?) } - b"content" => { + QName(b"content") => { entry.content = Some(Content::from_xml(reader, element.attributes())?) } n => { - if let Some((ns, name)) = extension_name(element.name()) { + if let Some(ns) = element.name().prefix() { parse_extension( reader, element.attributes(), ns, - name, + element.name().local_name(), &mut entry.extensions, )?; } else { reader - .read_to_end(n, &mut Vec::new()) + .read_to_end_into(n, &mut Vec::new()) .map_err(XmlError::new)?; } } @@ -573,24 +576,24 @@ impl FromXml for Entry { impl ToXml for Entry { fn to_xml(&self, writer: &mut Writer) -> Result<(), XmlError> { - let name = b"entry"; + let name = "entry"; writer - .write_event(Event::Start(BytesStart::borrowed(name, name.len()))) + .write_event(Event::Start(BytesStart::new(name))) .map_err(XmlError::new)?; - writer.write_object_named(&self.title, b"title")?; - writer.write_text_element(b"id", &*self.id)?; - writer.write_text_element(b"updated", &*self.updated.to_rfc3339())?; + writer.write_object_named(&self.title, "title")?; + writer.write_text_element("id", &self.id)?; + writer.write_text_element("updated", &self.updated.to_rfc3339())?; writer.write_objects_named(&self.authors, "author")?; writer.write_objects(&self.categories)?; writer.write_objects_named(&self.contributors, "contributor")?; writer.write_objects(&self.links)?; if let Some(ref published) = self.published { - writer.write_text_element(b"published", &published.to_rfc3339())?; + writer.write_text_element("published", &published.to_rfc3339())?; } if let Some(ref rights) = self.rights { - writer.write_object_named(rights, b"rights")?; + writer.write_object_named(rights, "rights")?; } if let Some(ref source) = self.source { @@ -598,7 +601,7 @@ impl ToXml for Entry { } if let Some(ref summary) = self.summary { - writer.write_object_named(summary, b"summary")?; + writer.write_object_named(summary, "summary")?; } if let Some(ref content) = self.content { @@ -612,7 +615,7 @@ impl ToXml for Entry { } writer - .write_event(Event::End(BytesEnd::borrowed(name))) + .write_event(Event::End(BytesEnd::new(name))) .map_err(XmlError::new)?; Ok(()) diff --git a/src/extension/mod.rs b/src/extension/mod.rs index c37c248..5367673 100644 --- a/src/extension/mod.rs +++ b/src/extension/mod.rs @@ -182,8 +182,7 @@ impl Extension { impl ToXml for Extension { fn to_xml(&self, writer: &mut Writer) -> Result<(), XmlError> { - let name = self.name.as_bytes(); - let mut element = BytesStart::borrowed(name, name.len()); + let mut element = BytesStart::new(&self.name); element.extend_attributes(self.attrs.iter().map(|a| (a.0.as_bytes(), a.1.as_bytes()))); writer .write_event(Event::Start(element)) @@ -191,7 +190,7 @@ impl ToXml for Extension { if let Some(value) = self.value.as_ref() { writer - .write_event(Event::Text(BytesText::from_escaped(value.as_bytes()))) + .write_event(Event::Text(BytesText::new(value))) .map_err(XmlError::new)?; } @@ -200,7 +199,7 @@ impl ToXml for Extension { } writer - .write_event(Event::End(BytesEnd::borrowed(name))) + .write_event(Event::End(BytesEnd::new(&self.name))) .map_err(XmlError::new)?; Ok(()) } diff --git a/src/extension/util.rs b/src/extension/util.rs index 5a48b84..54bbfc9 100644 --- a/src/extension/util.rs +++ b/src/extension/util.rs @@ -1,50 +1,48 @@ use std::collections::BTreeMap; use std::io::BufRead; -use std::str; use quick_xml::events::attributes::Attributes; use quick_xml::events::Event; +use quick_xml::name::{LocalName, Prefix}; use quick_xml::Reader; use crate::error::{Error, XmlError}; use crate::extension::{Extension, ExtensionMap}; -pub fn extension_name(element_name: &[u8]) -> Option<(&[u8], &[u8])> { - let mut split = element_name.splitn(2, |b| *b == b':'); - match split.next() { - Some(b"") | None => None, - Some(ns) => split.next().map(|name| (ns, name)), - } -} - -pub fn parse_extension( +pub fn parse_extension<'d, R>( reader: &mut Reader, atts: Attributes<'_>, - ns: &[u8], - name: &[u8], + ns: Prefix<'d>, + name: LocalName<'d>, extensions: &mut ExtensionMap, ) -> Result<(), Error> where R: BufRead, { - let ns = str::from_utf8(ns)?; - let name = str::from_utf8(name)?; + let ns = reader + .decoder() + .decode(ns.as_ref()) + .map_err(XmlError::new)?; let ext = parse_extension_element(reader, atts)?; - if !extensions.contains_key(ns) { + if !extensions.contains_key(ns.as_ref()) { extensions.insert(ns.to_string(), BTreeMap::new()); } - let map = match extensions.get_mut(ns) { + let map = match extensions.get_mut(ns.as_ref()) { Some(map) => map, None => unreachable!(), }; - if !map.contains_key(name) { + let name = reader + .decoder() + .decode(name.as_ref()) + .map_err(XmlError::new)?; + if !map.contains_key(name.as_ref()) { map.insert(name.to_string(), Vec::new()); } - let items = match map.get_mut(name) { + let items = match map.get_mut(name.as_ref()) { Some(items) => items, None => unreachable!(), }; @@ -62,24 +60,32 @@ fn parse_extension_element( let mut buf = Vec::new(); for attr in atts.with_checks(false).flatten() { - let key = str::from_utf8(attr.key)?; + let key_local_name = attr.key.local_name(); + let key = reader + .decoder() + .decode(key_local_name.as_ref()) + .map_err(XmlError::new)?; let value = attr - .unescape_and_decode_value(reader) + .decode_and_unescape_value(reader) .map_err(XmlError::new)?; - extension.attrs.insert(key.to_string(), value); + extension.attrs.insert(key.to_string(), value.to_string()); } loop { - match reader.read_event(&mut buf).map_err(XmlError::new)? { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { Event::Start(element) => { let ext = parse_extension_element(reader, element.attributes())?; - let name = str::from_utf8(element.local_name())?; + let element_local_name = element.local_name(); + let name = reader + .decoder() + .decode(element_local_name.as_ref()) + .map_err(XmlError::new)?; - if !extension.children.contains_key(name) { + if !extension.children.contains_key(&*name) { extension.children.insert(name.to_string(), Vec::new()); } - let items = match extension.children.get_mut(name) { + let items = match extension.children.get_mut(&*name) { Some(items) => items, None => unreachable!(), }; @@ -87,19 +93,32 @@ fn parse_extension_element( items.push(ext); } Event::CData(element) => { - extension.value = Some(reader.decode(&element).into()); + extension.value = Some( + reader + .decoder() + .decode(&*element) + .map_err(XmlError::new)? + .into(), + ) + .filter(|s: &String| !s.is_empty()); } Event::Text(element) => { extension.value = Some( - element - .unescape_and_decode(reader) + reader + .decoder() + .decode(&*element) .map_err(XmlError::new)? .trim() - .to_string(), - ); + .into(), + ) + .filter(|s: &String| !s.is_empty()); } Event::End(element) => { - extension.name = reader.decode(element.name()).into(); + extension.name = reader + .decoder() + .decode(element.name().as_ref()) + .map_err(XmlError::new)? + .into(); break; } Event::Eof => return Err(Error::Eof), diff --git a/src/feed.rs b/src/feed.rs index 57ed1bb..a9d5a52 100644 --- a/src/feed.rs +++ b/src/feed.rs @@ -5,13 +5,14 @@ use std::str::{self, FromStr}; use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event}; // use quick_xml::Error as XmlError; +use quick_xml::name::QName; use quick_xml::Reader; use quick_xml::Writer; use crate::category::Category; use crate::entry::Entry; use crate::error::{Error, XmlError}; -use crate::extension::util::{extension_name, parse_extension}; +use crate::extension::util::parse_extension; use crate::extension::ExtensionMap; use crate::fromxml::FromXml; use crate::generator::Generator; @@ -97,9 +98,13 @@ impl Feed { let mut buf = Vec::new(); loop { - match reader.read_event(&mut buf).map_err(XmlError::new)? { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { Event::Start(element) => { - if element.name() == b"feed" { + if reader + .decoder() + .decode(element.name().as_ref()) + .map_or(false, |n| n == "feed") + { return Feed::from_xml(&mut reader, element.attributes()); } else { return Err(Error::InvalidStartTag); @@ -132,10 +137,10 @@ impl Feed { pub fn write_to(&self, writer: W) -> Result { let mut writer = Writer::new(writer); writer - .write_event(Event::Decl(BytesDecl::new(b"1.0", None, None))) + .write_event(Event::Decl(BytesDecl::new("1.0", None, None))) .map_err(XmlError::new)?; writer - .write_event(Event::Text(BytesText::from_escaped("\n".as_bytes()))) + .write_event(Event::Text(BytesText::new("\n"))) .map_err(XmlError::new)?; self.to_xml(&mut writer)?; Ok(writer.into_inner()) @@ -682,74 +687,93 @@ impl FromXml for Feed { for attr in atts.with_checks(false).flatten() { match attr.key { - b"xml:base" => { + QName(b"xml:base") => { feed.base = Some( - attr.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, + attr.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), ) } - b"xml:lang" => { + QName(b"xml:lang") => { feed.lang = Some( - attr.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, + attr.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), ) } - b"xmlns:dc" => {} - attr_key if attr_key.starts_with(b"xmlns:") => { - let ns = str::from_utf8(&attr_key[6..])?.to_string(); + QName(b"xmlns:dc") => {} + attr_key + if attr_key + .prefix() + .and_then(|p| { + reader + .decoder() + .decode(p.as_ref()) + .map(|s| s == "xmlns") + .ok() + }) + .unwrap_or(false) => + { + let ns = reader + .decoder() + .decode(attr_key.local_name().as_ref()) + .map_err(XmlError::new)? + .to_string(); let ns_url = attr - .unescape_and_decode_value(reader) + .decode_and_unescape_value(reader) .map_err(XmlError::new)?; - feed.namespaces.insert(ns, ns_url); + feed.namespaces.insert(ns, ns_url.to_string()); } _ => {} } } loop { - match reader.read_event(&mut buf).map_err(XmlError::new)? { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { Event::Start(element) => match element.name() { - b"title" => feed.title = Text::from_xml(reader, element.attributes())?, - b"id" => feed.id = atom_text(reader)?.unwrap_or_default(), - b"updated" => { + QName(b"title") => feed.title = Text::from_xml(reader, element.attributes())?, + QName(b"id") => feed.id = atom_text(reader)?.unwrap_or_default(), + QName(b"updated") => { feed.updated = atom_datetime(reader)?.unwrap_or_else(default_fixed_datetime) } - b"author" => feed + QName(b"author") => feed .authors .push(Person::from_xml(reader, element.attributes())?), - b"category" => feed + QName(b"category") => feed .categories .push(Category::from_xml(reader, element.attributes())?), - b"contributor" => feed + QName(b"contributor") => feed .contributors .push(Person::from_xml(reader, element.attributes())?), - b"generator" => { + QName(b"generator") => { feed.generator = Some(Generator::from_xml(reader, element.attributes())?) } - b"icon" => feed.icon = atom_text(reader)?, - b"link" => feed + QName(b"icon") => feed.icon = atom_text(reader)?, + QName(b"link") => feed .links .push(Link::from_xml(reader, element.attributes())?), - b"logo" => feed.logo = atom_text(reader)?, - b"rights" => feed.rights = Some(Text::from_xml(reader, element.attributes())?), - b"subtitle" => { + QName(b"logo") => feed.logo = atom_text(reader)?, + QName(b"rights") => { + feed.rights = Some(Text::from_xml(reader, element.attributes())?) + } + QName(b"subtitle") => { feed.subtitle = Some(Text::from_xml(reader, element.attributes())?) } - b"entry" => feed + QName(b"entry") => feed .entries .push(Entry::from_xml(reader, element.attributes())?), n => { - if let Some((ns, name)) = extension_name(element.name()) { + if let Some(ns) = element.name().prefix() { parse_extension( reader, element.attributes(), ns, - name, + element.name().local_name(), &mut feed.extensions, )?; } else { reader - .read_to_end(n, &mut Vec::new()) + .read_to_end_into(n, &mut Vec::new()) .map_err(XmlError::new)?; } } @@ -768,8 +792,8 @@ impl FromXml for Feed { impl ToXml for Feed { fn to_xml(&self, writer: &mut Writer) -> Result<(), XmlError> { - let name = b"feed"; - let mut element = BytesStart::borrowed(name, name.len()); + let name = "feed"; + let mut element = BytesStart::new(name); element.push_attribute(("xmlns", "http://www.w3.org/2005/Atom")); for (ns, uri) in &self.namespaces { @@ -787,9 +811,9 @@ impl ToXml for Feed { writer .write_event(Event::Start(element)) .map_err(XmlError::new)?; - writer.write_object_named(&self.title, b"title")?; - writer.write_text_element(b"id", &*self.id)?; - writer.write_text_element(b"updated", &*self.updated.to_rfc3339())?; + writer.write_object_named(&self.title, "title")?; + writer.write_text_element("id", &self.id)?; + writer.write_text_element("updated", &self.updated.to_rfc3339())?; writer.write_objects_named(&self.authors, "author")?; writer.write_objects(&self.categories)?; writer.write_objects_named(&self.contributors, "contributor")?; @@ -799,21 +823,21 @@ impl ToXml for Feed { } if let Some(ref icon) = self.icon { - writer.write_text_element(b"icon", &**icon)?; + writer.write_text_element("icon", icon)?; } writer.write_objects(&self.links)?; if let Some(ref logo) = self.logo { - writer.write_text_element(b"logo", &**logo)?; + writer.write_text_element("logo", logo)?; } if let Some(ref rights) = self.rights { - writer.write_object_named(rights, b"rights")?; + writer.write_object_named(rights, "rights")?; } if let Some(ref subtitle) = self.subtitle { - writer.write_object_named(subtitle, b"subtitle")?; + writer.write_object_named(subtitle, "subtitle")?; } writer.write_objects(&self.entries)?; @@ -825,7 +849,7 @@ impl ToXml for Feed { } writer - .write_event(Event::End(BytesEnd::borrowed(name))) + .write_event(Event::End(BytesEnd::new(name))) .map_err(XmlError::new)?; Ok(()) diff --git a/src/generator.rs b/src/generator.rs index ed7de21..085853a 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -138,18 +138,20 @@ impl FromXml for Generator { let mut generator = Generator::default(); for att in atts.with_checks(false).flatten() { - match att.key { + match att.key.local_name().as_ref() { b"uri" => { generator.uri = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), + ); } b"version" => { generator.version = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), + ); } _ => {} } @@ -163,8 +165,8 @@ impl FromXml for Generator { impl ToXml for Generator { fn to_xml(&self, writer: &mut Writer) -> Result<(), XmlError> { - let name = b"generator"; - let mut element = BytesStart::borrowed(name, name.len()); + let name = "generator"; + let mut element = BytesStart::new(name); if let Some(ref uri) = self.uri { element.push_attribute(("uri", &**uri)); @@ -178,10 +180,10 @@ impl ToXml for Generator { .write_event(Event::Start(element)) .map_err(XmlError::new)?; writer - .write_event(Event::Text(BytesText::from_escaped(self.value.as_bytes()))) + .write_event(Event::Text(BytesText::new(&self.value))) .map_err(XmlError::new)?; writer - .write_event(Event::End(BytesEnd::borrowed(name))) + .write_event(Event::End(BytesEnd::new(name))) .map_err(XmlError::new)?; Ok(()) diff --git a/src/link.rs b/src/link.rs index 33fdfa1..cf07ef8 100644 --- a/src/link.rs +++ b/src/link.rs @@ -2,6 +2,7 @@ use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesStart, Event}; +use quick_xml::name::QName; use quick_xml::Reader; use quick_xml::Writer; @@ -248,22 +249,32 @@ impl FromXml for Link { fn from_xml_inner( reader: &mut Reader, mut atts: Attributes<'_>, - ) -> Result { + ) -> quick_xml::Result { let mut link = Link::default(); for att in atts.with_checks(false).flatten() { match att.key { - b"href" => link.href = att.unescape_and_decode_value(reader)?, - b"rel" => link.rel = att.unescape_and_decode_value(reader)?, - b"hreflang" => link.hreflang = Some(att.unescape_and_decode_value(reader)?), - b"type" => link.mime_type = Some(att.unescape_and_decode_value(reader)?), - b"title" => link.title = Some(att.unescape_and_decode_value(reader)?), - b"length" => link.length = Some(att.unescape_and_decode_value(reader)?), + QName(b"href") => { + link.href = att.decode_and_unescape_value(reader)?.to_string() + } + QName(b"rel") => link.rel = att.decode_and_unescape_value(reader)?.to_string(), + QName(b"hreflang") => { + link.hreflang = Some(att.decode_and_unescape_value(reader)?.to_string()) + } + QName(b"type") => { + link.mime_type = Some(att.decode_and_unescape_value(reader)?.to_string()) + } + QName(b"title") => { + link.title = Some(att.decode_and_unescape_value(reader)?.to_string()) + } + QName(b"length") => { + link.length = Some(att.decode_and_unescape_value(reader)?.to_string()) + } _ => {} } } - reader.read_to_end(b"link", &mut Vec::new())?; + reader.read_to_end_into(QName(b"link"), &mut Vec::new())?; Ok(link) } @@ -275,8 +286,7 @@ impl FromXml for Link { impl ToXml for Link { fn to_xml(&self, writer: &mut Writer) -> Result<(), XmlError> { - let name = b"link"; - let mut element = BytesStart::borrowed(name, name.len()); + let mut element = BytesStart::new("link"); element.push_attribute(("href", &*self.href)); element.push_attribute(("rel", &*self.rel)); diff --git a/src/person.rs b/src/person.rs index 05d93f2..0b27258 100644 --- a/src/person.rs +++ b/src/person.rs @@ -2,6 +2,7 @@ use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesEnd, BytesStart, Event}; +use quick_xml::name::QName; use quick_xml::Reader; use quick_xml::Writer; @@ -135,14 +136,16 @@ impl FromXml for Person { let mut buf = Vec::new(); loop { - match reader.read_event(&mut buf).map_err(XmlError::new)? { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { Event::Start(element) => match element.name() { - b"name" => person.name = atom_text(reader)?.unwrap_or_default(), - b"email" => person.email = atom_text(reader)?, - b"uri" => person.uri = atom_text(reader)?, - n => reader - .read_to_end(n, &mut Vec::new()) - .map_err(XmlError::new)?, + QName(b"name") => person.name = atom_text(reader)?.unwrap_or_default(), + QName(b"email") => person.email = atom_text(reader)?, + QName(b"uri") => person.uri = atom_text(reader)?, + n => { + reader + .read_to_end_into(n, &mut Vec::new()) + .map_err(XmlError::new)?; + } }, Event::End(_) => break, Event::Eof => return Err(Error::Eof), @@ -157,27 +160,25 @@ impl FromXml for Person { } impl ToXmlNamed for Person { - fn to_xml_named(&self, writer: &mut Writer, name: N) -> Result<(), XmlError> + fn to_xml_named(&self, writer: &mut Writer, name: &str) -> Result<(), XmlError> where W: Write, - N: AsRef<[u8]>, { - let name = name.as_ref(); writer - .write_event(Event::Start(BytesStart::borrowed(name, name.len()))) + .write_event(Event::Start(BytesStart::new(name))) .map_err(XmlError::new)?; - writer.write_text_element(b"name", &*self.name)?; + writer.write_text_element("name", &self.name)?; if let Some(ref email) = self.email { - writer.write_text_element(b"email", &*email)?; + writer.write_text_element("email", email)?; } if let Some(ref uri) = self.uri { - writer.write_text_element(b"uri", &*uri)?; + writer.write_text_element("uri", uri)?; } writer - .write_event(Event::End(BytesEnd::borrowed(name))) + .write_event(Event::End(BytesEnd::new(name))) .map_err(XmlError::new)?; Ok(()) diff --git a/src/source.rs b/src/source.rs index 59191a1..1bfa622 100644 --- a/src/source.rs +++ b/src/source.rs @@ -2,6 +2,7 @@ use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesEnd, BytesStart, Event}; +use quick_xml::name::QName; use quick_xml::Reader; use quick_xml::Writer; @@ -454,40 +455,42 @@ impl FromXml for Source { let mut buf = Vec::new(); loop { - match reader.read_event(&mut buf).map_err(XmlError::new)? { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { Event::Start(element) => match element.name() { - b"id" => source.id = atom_text(reader)?.unwrap_or_default(), - b"title" => source.title = Text::from_xml(reader, element.attributes())?, - b"updated" => { + QName(b"id") => source.id = atom_text(reader)?.unwrap_or_default(), + QName(b"title") => source.title = Text::from_xml(reader, element.attributes())?, + QName(b"updated") => { source.updated = atom_datetime(reader)?.unwrap_or_else(default_fixed_datetime) } - b"author" => source + QName(b"author") => source .authors .push(Person::from_xml(reader, element.attributes())?), - b"category" => source + QName(b"category") => source .categories .push(Category::from_xml(reader, element.attributes())?), - b"contributor" => source + QName(b"contributor") => source .contributors .push(Person::from_xml(reader, element.attributes())?), - b"generator" => { + QName(b"generator") => { source.generator = Some(Generator::from_xml(reader, element.attributes())?) } - b"icon" => source.icon = atom_text(reader)?, - b"link" => source + QName(b"icon") => source.icon = atom_text(reader)?, + QName(b"link") => source .links .push(Link::from_xml(reader, element.attributes())?), - b"logo" => source.logo = atom_text(reader)?, - b"rights" => { + QName(b"logo") => source.logo = atom_text(reader)?, + QName(b"rights") => { source.rights = Some(Text::from_xml(reader, element.attributes())?) } - b"subtitle" => { + QName(b"subtitle") => { source.subtitle = Some(Text::from_xml(reader, element.attributes())?) } - n => reader - .read_to_end(n, &mut Vec::new()) - .map_err(XmlError::new)?, + n => { + reader + .read_to_end_into(n, &mut Vec::new()) + .map_err(XmlError::new)?; + } }, Event::End(_) => break, Event::Eof => return Err(Error::Eof), @@ -503,13 +506,13 @@ impl FromXml for Source { impl ToXml for Source { fn to_xml(&self, writer: &mut Writer) -> Result<(), XmlError> { - let name = b"source"; + let name = "source"; writer - .write_event(Event::Start(BytesStart::borrowed(name, name.len()))) + .write_event(Event::Start(BytesStart::new(name))) .map_err(XmlError::new)?; - writer.write_object_named(&self.title, b"title")?; - writer.write_text_element(b"id", &*self.id)?; - writer.write_text_element(b"updated", &self.updated.to_rfc3339())?; + writer.write_object_named(&self.title, "title")?; + writer.write_text_element("id", &self.id)?; + writer.write_text_element("updated", &self.updated.to_rfc3339())?; writer.write_objects_named(&self.authors, "author")?; writer.write_objects(&self.categories)?; writer.write_objects_named(&self.contributors, "contributor")?; @@ -519,25 +522,25 @@ impl ToXml for Source { } if let Some(ref icon) = self.icon { - writer.write_text_element(b"icon", &**icon)?; + writer.write_text_element("icon", icon)?; } writer.write_objects(&self.links)?; if let Some(ref logo) = self.logo { - writer.write_text_element(b"logo", &**logo)?; + writer.write_text_element("logo", logo)?; } if let Some(ref rights) = self.rights { - writer.write_object_named(rights, b"rights")?; + writer.write_object_named(rights, "rights")?; } if let Some(ref subtitle) = self.subtitle { - writer.write_object_named(subtitle, b"subtitle")?; + writer.write_object_named(subtitle, "subtitle")?; } writer - .write_event(Event::End(BytesEnd::borrowed(name))) + .write_event(Event::End(BytesEnd::new(name))) .map_err(XmlError::new)?; Ok(()) diff --git a/src/text.rs b/src/text.rs index 8ca6333..d548350 100644 --- a/src/text.rs +++ b/src/text.rs @@ -6,6 +6,7 @@ use std::str::FromStr; use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; +use quick_xml::name::QName; use quick_xml::Reader; use quick_xml::Writer; @@ -163,21 +164,23 @@ impl FromXml for Text { for att in atts.with_checks(false).flatten() { match att.key { - b"xml:base" => { + QName(b"xml:base") => { text.base = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), ) } - b"xml:lang" => { + QName(b"xml:lang") => { text.lang = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, + att.decode_and_unescape_value(reader) + .map_err(XmlError::new)? + .to_string(), ) } - b"type" => { + QName(b"type") => { text.r#type = att - .unescape_and_decode_value(reader) + .decode_and_unescape_value(reader) .map_err(XmlError::new)? .parse()? } @@ -198,13 +201,11 @@ impl FromXml for Text { } impl ToXmlNamed for Text { - fn to_xml_named(&self, writer: &mut Writer, name: N) -> Result<(), XmlError> + fn to_xml_named(&self, writer: &mut Writer, name: &str) -> Result<(), XmlError> where W: Write, - N: AsRef<[u8]>, { - let name = name.as_ref(); - let mut element = BytesStart::borrowed(name, name.len()); + let mut element = BytesStart::new(name); if let Some(ref base) = self.base { element.push_attribute(("xml:base", base.as_str())); } @@ -219,15 +220,15 @@ impl ToXmlNamed for Text { .map_err(XmlError::new)?; if self.r#type == TextType::Xhtml { writer - .write_event(Event::Text(BytesText::from_escaped(self.value.as_bytes()))) + .write_event(Event::Text(BytesText::from_escaped(&self.value))) .map_err(XmlError::new)?; } else { writer - .write_event(Event::Text(BytesText::from_plain_str(self.value.as_str()))) + .write_event(Event::Text(BytesText::new(&self.value))) .map_err(XmlError::new)?; } writer - .write_event(Event::End(BytesEnd::borrowed(name))) + .write_event(Event::End(BytesEnd::new(name))) .map_err(XmlError::new)?; Ok(()) diff --git a/src/toxml.rs b/src/toxml.rs index 22e3147..a67c0ec 100644 --- a/src/toxml.rs +++ b/src/toxml.rs @@ -16,84 +16,53 @@ impl<'a, T: ToXml> ToXml for &'a T { } pub(crate) trait ToXmlNamed { - fn to_xml_named(&self, writer: &mut Writer, name: N) -> Result<(), XmlError> + fn to_xml_named(&self, writer: &mut Writer, name: &str) -> Result<(), XmlError> where - W: Write, - N: AsRef<[u8]>; + W: Write; } impl<'a, T: ToXmlNamed> ToXmlNamed for &'a T { - fn to_xml_named(&self, writer: &mut Writer, name: N) -> Result<(), XmlError> + fn to_xml_named(&self, writer: &mut Writer, name: &str) -> Result<(), XmlError> where W: Write, - N: AsRef<[u8]>, { (*self).to_xml_named(writer, name) } } pub(crate) trait WriterExt { - fn write_text_element(&mut self, name: N, text: T) -> Result<(), XmlError> - where - N: AsRef<[u8]>, - T: AsRef<[u8]>; - - fn write_text_elements(&mut self, name: N, values: I) -> Result<(), XmlError> - where - N: AsRef<[u8]>, - T: AsRef<[u8]>, - I: IntoIterator; + fn write_text_element(&mut self, name: &str, text: &str) -> Result<(), XmlError>; fn write_object(&mut self, object: T) -> Result<(), XmlError> where T: ToXml; - fn write_object_named(&mut self, object: T, name: N) -> Result<(), XmlError> + fn write_object_named(&mut self, object: T, name: &str) -> Result<(), XmlError> where - T: ToXmlNamed, - N: AsRef<[u8]>; + T: ToXmlNamed; fn write_objects(&mut self, objects: I) -> Result<(), XmlError> where T: ToXml, I: IntoIterator; - fn write_objects_named(&mut self, objects: I, name: N) -> Result<(), XmlError> + fn write_objects_named(&mut self, objects: I, name: &str) -> Result<(), XmlError> where T: ToXmlNamed, - I: IntoIterator, - N: AsRef<[u8]>; + I: IntoIterator; } impl WriterExt for Writer { - fn write_text_element(&mut self, name: N, text: T) -> Result<(), XmlError> - where - N: AsRef<[u8]>, - T: AsRef<[u8]>, - { - let name = name.as_ref(); - self.write_event(Event::Start(BytesStart::borrowed(name, name.len()))) + fn write_text_element(&mut self, name: &str, text: &str) -> Result<(), XmlError> { + self.write_event(Event::Start(BytesStart::new(name))) .map_err(XmlError::new)?; - self.write_event(Event::Text(BytesText::from_escaped(text.as_ref()))) + self.write_event(Event::Text(BytesText::new(text))) .map_err(XmlError::new)?; - self.write_event(Event::End(BytesEnd::borrowed(name))) + self.write_event(Event::End(BytesEnd::new(name))) .map_err(XmlError::new)?; Ok(()) } - fn write_text_elements(&mut self, name: N, values: I) -> Result<(), XmlError> - where - N: AsRef<[u8]>, - T: AsRef<[u8]>, - I: IntoIterator, - { - for value in values { - self.write_text_element(name.as_ref(), value)?; - } - - Ok(()) - } - fn write_object(&mut self, object: T) -> Result<(), XmlError> where T: ToXml, @@ -101,10 +70,9 @@ impl WriterExt for Writer { object.to_xml(self) } - fn write_object_named(&mut self, object: T, name: N) -> Result<(), XmlError> + fn write_object_named(&mut self, object: T, name: &str) -> Result<(), XmlError> where T: ToXmlNamed, - N: AsRef<[u8]>, { object.to_xml_named(self, name) } @@ -121,14 +89,13 @@ impl WriterExt for Writer { Ok(()) } - fn write_objects_named(&mut self, objects: I, name: N) -> Result<(), XmlError> + fn write_objects_named(&mut self, objects: I, name: &str) -> Result<(), XmlError> where T: ToXmlNamed, I: IntoIterator, - N: AsRef<[u8]>, { for object in objects { - object.to_xml_named(self, name.as_ref())?; + object.to_xml_named(self, name)?; } Ok(()) diff --git a/src/util.rs b/src/util.rs index fa7bb7c..7b2e5f9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -29,11 +29,20 @@ pub fn atom_text(reader: &mut Reader) -> Result, E let mut result = String::new(); loop { - match reader.read_event(&mut innerbuf).map_err(XmlError::new)? { + match reader + .read_event_into(&mut innerbuf) + .map_err(XmlError::new)? + { Event::Start(start) => { depth += 1; result.push('<'); - result.push_str(&start.unescape_and_decode(reader).map_err(XmlError::new)?); + result.push_str( + reader + .decoder() + .decode(&*start) + .map_err(XmlError::new)? + .as_ref(), + ); result.push('>'); } Event::End(end) => { @@ -42,24 +51,40 @@ pub fn atom_text(reader: &mut Reader) -> Result, E } depth -= 1; result.push_str("'); } Event::Empty(start) => { result.push('<'); - result.push_str(&start.unescape_and_decode(reader).map_err(XmlError::new)?); + result.push_str( + reader + .decoder() + .decode(&*start) + .map_err(XmlError::new)? + .as_ref(), + ); result.push_str("/>"); } Event::CData(text) => { - let decoded = text.unescape_and_decode(reader).map_err(XmlError::new)?; + let decoded = text + .escape() + .map_err(XmlError::new)? + .unescape() + .map_err(XmlError::new)?; result.push_str(&decoded); } Event::Text(text) => { - let decoded = text.unescape_and_decode(reader).map_err(XmlError::new)?; + let decoded = text.unescape().map_err(XmlError::new)?; result.push_str(&decoded); } Event::Comment(text) => { - let decoded = text.unescape_and_decode(reader).map_err(XmlError::new)?; + let decoded = text.unescape().map_err(XmlError::new)?; result.push_str(""); @@ -86,11 +111,20 @@ pub fn atom_xhtml(reader: &mut Reader) -> Result, let mut result = String::new(); loop { - match reader.read_event(&mut innerbuf).map_err(XmlError::new)? { + match reader + .read_event_into(&mut innerbuf) + .map_err(XmlError::new)? + { Event::Start(start) => { depth += 1; result.push('<'); - result.push_str(&start.unescape_and_decode(reader).map_err(XmlError::new)?); + result.push_str( + reader + .decoder() + .decode(&*start) + .map_err(XmlError::new)? + .as_ref(), + ); result.push('>'); } Event::End(end) => { @@ -99,24 +133,45 @@ pub fn atom_xhtml(reader: &mut Reader) -> Result, } depth -= 1; result.push_str("'); } Event::Empty(start) => { result.push('<'); - result.push_str(&start.unescape_and_decode(reader).map_err(XmlError::new)?); + result.push_str( + reader + .decoder() + .decode(&*start) + .map_err(XmlError::new)? + .as_ref(), + ); result.push_str("/>"); } Event::CData(text) => { - let decoded = reader.decode(text.escaped()); + let decoded = text + .escape() + .map_err(XmlError::new)? + .unescape() + .map_err(XmlError::new)?; result.push_str(&decoded); } Event::Text(text) => { - let decoded = reader.decode(text.escaped()); - result.push_str(&decoded); + result.push_str( + reader + .decoder() + .decode(&*text) + .map_err(XmlError::new)? + .as_ref(), + ); } Event::Comment(text) => { - let decoded = text.unescape_and_decode(reader).map_err(XmlError::new)?; + let decoded = text.unescape().map_err(XmlError::new)?; result.push_str(""); @@ -150,17 +205,18 @@ pub fn atom_datetime(reader: &mut Reader) -> Result Result, Error> { let mut reader = Reader::from_reader(xml.as_bytes()); reader.expand_empty_elements(true); loop { let mut buf = Vec::new(); - match reader.read_event(&mut buf).map_err(XmlError::new)? { - Event::Start(element) if element.name() == b"text" => { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { + Event::Start(element) if element.name() == QName(b"text") => { return atom_text(&mut reader) } - Event::Start(element) if element.name() == b"raw" => { + Event::Start(element) if element.name() == QName(b"raw") => { return atom_xhtml(&mut reader) } Event::Start(_) => return Err(Error::InvalidStartTag),