From acad6b9bacc016863ba622fb21965686b80fffc8 Mon Sep 17 00:00:00 2001 From: Andrey Kutejko Date: Tue, 27 Dec 2022 13:48:50 +0100 Subject: [PATCH] Upgrade quick-xml to 0.27 --- .github/workflows/build.yml | 2 +- CHANGELOG.md | 3 +- Cargo.toml | 4 +- src/category.rs | 42 +++++-------- src/content.rs | 48 ++++++--------- src/entry.rs | 69 +++++++++++---------- src/extension/mod.rs | 7 +-- src/extension/util.rs | 58 +++++++++--------- src/feed.rs | 119 ++++++++++++++++++------------------ src/generator.rs | 27 ++++---- src/link.rs | 52 ++++++++-------- src/person.rs | 31 +++++----- src/source.rs | 69 +++++++++++---------- src/text.rs | 38 ++++-------- src/toxml.rs | 63 +++++-------------- src/util.rs | 88 ++++++++++++++++++-------- 16 files changed, 343 insertions(+), 377 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..1f659f5 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` and `derive_builder` to `0.12` [`#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..2f3e3d2 100644 --- a/src/category.rs +++ b/src/category.rs @@ -1,13 +1,13 @@ +use std::borrow::Cow; use std::io::{BufRead, Write}; -use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesStart, Event}; use quick_xml::Reader; use quick_xml::Writer; use crate::error::{Error, XmlError}; -use crate::fromxml::FromXml; use crate::toxml::ToXml; +use crate::util::{attr_value, decode}; /// Represents a category in an Atom feed #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -129,48 +129,34 @@ impl Category { } } -impl FromXml for Category { - fn from_xml( +impl Category { + pub(crate) fn from_xml<'s, B: BufRead>( reader: &mut Reader, - mut atts: Attributes<'_>, + element: &'s BytesStart<'s>, ) -> Result { let mut category = Category::default(); - for att in atts.with_checks(false).flatten() { - match att.key { - b"term" => { - category.term = att - .unescape_and_decode_value(reader) - .map_err(XmlError::new)? + for att in element.attributes().with_checks(false).flatten() { + match decode(att.key.as_ref(), reader)? { + Cow::Borrowed("term") => { + category.term = attr_value(&att, reader)?.to_string(); } - b"scheme" => { - category.scheme = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + Cow::Borrowed("scheme") => { + category.scheme = Some(attr_value(&att, reader)?.to_string()); } - b"label" => { - category.label = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + Cow::Borrowed("label") => { + category.label = Some(attr_value(&att, reader)?.to_string()); } _ => {} } } - - reader - .read_to_end(b"category", &mut Vec::new()) - .map_err(XmlError::new)?; - Ok(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..b944381 100644 --- a/src/content.rs +++ b/src/content.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; @@ -8,7 +9,7 @@ use quick_xml::Writer; use crate::error::{Error, XmlError}; use crate::fromxml::FromXml; use crate::toxml::ToXml; -use crate::util::{atom_text, atom_xhtml}; +use crate::util::{atom_text, atom_xhtml, attr_value, decode}; /// Represents the content of an Atom entry #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -173,30 +174,18 @@ impl FromXml for Content { let mut content = Content::default(); for att in atts.with_checks(false).flatten() { - match att.key { - b"xml:base" => { - content.base = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + match decode(att.key.as_ref(), reader)? { + Cow::Borrowed("xml:base") => { + content.base = Some(attr_value(&att, reader)?.to_string()); } - b"xml:lang" => { - content.lang = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + Cow::Borrowed("xml:lang") => { + content.lang = Some(attr_value(&att, reader)?.to_string()); } - b"type" => { - content.content_type = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + Cow::Borrowed("type") => { + content.content_type = Some(attr_value(&att, reader)?.to_string()); } - b"src" => { - content.src = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + Cow::Borrowed("src") => { + content.src = Some(attr_value(&att, reader)?.to_string()); } _ => {} } @@ -213,8 +202,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 +233,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(()) @@ -272,6 +261,7 @@ impl ContentBuilder { mod test { use super::*; use crate::error::Error; + use crate::util::decode; fn lines(text: &str) -> Vec<&str> { text.lines() @@ -293,9 +283,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 decode(element.name().as_ref(), &reader)? == "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..d351632 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; @@ -16,7 +17,7 @@ use crate::person::Person; use crate::source::Source; use crate::text::Text; use crate::toxml::{ToXml, WriterExt}; -use crate::util::{atom_datetime, atom_text, default_fixed_datetime, FixedDateTime}; +use crate::util::{atom_datetime, atom_text, decode, default_fixed_datetime, skip, FixedDateTime}; /// Represents an entry in an Atom feed #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -512,39 +513,45 @@ impl FromXml for Entry { let mut buf = Vec::new(); loop { - match reader.read_event(&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" => { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { + Event::Start(element) => match decode(element.name().as_ref(), reader)? { + Cow::Borrowed("id") => entry.id = atom_text(reader)?.unwrap_or_default(), + Cow::Borrowed("title") => { + entry.title = Text::from_xml(reader, element.attributes())? + } + Cow::Borrowed("updated") => { entry.updated = atom_datetime(reader)?.unwrap_or_else(default_fixed_datetime) } - b"author" => entry + Cow::Borrowed("author") => entry .authors .push(Person::from_xml(reader, element.attributes())?), - b"category" => entry - .categories - .push(Category::from_xml(reader, element.attributes())?), - b"contributor" => entry + Cow::Borrowed("category") => { + entry.categories.push(Category::from_xml(reader, &element)?); + skip(element.name(), reader)?; + } + Cow::Borrowed("contributor") => entry .contributors .push(Person::from_xml(reader, element.attributes())?), - 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" => { + Cow::Borrowed("link") => { + entry.links.push(Link::from_xml(reader, &element)?); + skip(element.name(), reader)?; + } + Cow::Borrowed("published") => entry.published = atom_datetime(reader)?, + Cow::Borrowed("rights") => { + entry.rights = Some(Text::from_xml(reader, element.attributes())?) + } + Cow::Borrowed("source") => { entry.source = Some(Source::from_xml(reader, element.attributes())?) } - b"summary" => { + Cow::Borrowed("summary") => { entry.summary = Some(Text::from_xml(reader, element.attributes())?) } - b"content" => { + Cow::Borrowed("content") => { entry.content = Some(Content::from_xml(reader, element.attributes())?) } n => { - if let Some((ns, name)) = extension_name(element.name()) { + if let Some((ns, name)) = extension_name(n.as_ref()) { parse_extension( reader, element.attributes(), @@ -553,9 +560,7 @@ impl FromXml for Entry { &mut entry.extensions, )?; } else { - reader - .read_to_end(n, &mut Vec::new()) - .map_err(XmlError::new)?; + skip(element.name(), reader)?; } } }, @@ -573,24 +578,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 +603,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 +617,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..1d67f05 100644 --- a/src/extension/util.rs +++ b/src/extension/util.rs @@ -1,6 +1,5 @@ use std::collections::BTreeMap; use std::io::BufRead; -use std::str; use quick_xml::events::attributes::Attributes; use quick_xml::events::Event; @@ -8,27 +7,25 @@ use quick_xml::Reader; use crate::error::{Error, XmlError}; use crate::extension::{Extension, ExtensionMap}; +use crate::util::{attr_value, decode}; -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 extension_name(element_name: &str) -> Option<(&str, &str)> { + let mut split = element_name.splitn(2, ':'); + let ns = split.next().filter(|ns| !ns.is_empty())?; + let name = split.next()?; + Some((ns, name)) } pub fn parse_extension( reader: &mut Reader, atts: Attributes<'_>, - ns: &[u8], - name: &[u8], + ns: &str, + name: &str, extensions: &mut ExtensionMap, ) -> Result<(), Error> where R: BufRead, { - let ns = str::from_utf8(ns)?; - let name = str::from_utf8(name)?; let ext = parse_extension_element(reader, atts)?; if !extensions.contains_key(ns) { @@ -62,24 +59,23 @@ 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 value = attr - .unescape_and_decode_value(reader) - .map_err(XmlError::new)?; - extension.attrs.insert(key.to_string(), value); + let key = decode(attr.key.local_name().as_ref(), reader)?.to_string(); + let value = attr_value(&attr, reader)?.to_string(); + extension.attrs.insert(key, value); } 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 = decode(element_local_name.as_ref(), reader)?; - 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 +83,23 @@ fn parse_extension_element( items.push(ext); } Event::CData(element) => { - extension.value = Some(reader.decode(&element).into()); + let value = decode(&element, reader)?; + if value.is_empty() { + extension.value = None; + } else { + extension.value = Some(value.into()); + } } Event::Text(element) => { - extension.value = Some( - element - .unescape_and_decode(reader) - .map_err(XmlError::new)? - .trim() - .to_string(), - ); + let value = decode(&element, reader)?; + if value.is_empty() { + extension.value = None; + } else { + extension.value = Some(value.into()); + } } Event::End(element) => { - extension.name = reader.decode(element.name()).into(); + extension.name = decode(element.name().as_ref(), reader)?.into(); break; } Event::Eof => return Err(Error::Eof), diff --git a/src/feed.rs b/src/feed.rs index 57ed1bb..f9fea92 100644 --- a/src/feed.rs +++ b/src/feed.rs @@ -1,12 +1,11 @@ +use std::borrow::Cow; use std::collections::BTreeMap; use std::io::{BufRead, Write}; 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::Reader; -use quick_xml::Writer; +use quick_xml::{Reader, Writer}; use crate::category::Category; use crate::entry::Entry; @@ -19,7 +18,9 @@ use crate::link::Link; use crate::person::Person; use crate::text::Text; use crate::toxml::{ToXml, WriterExt}; -use crate::util::{atom_datetime, atom_text, default_fixed_datetime, FixedDateTime}; +use crate::util::{ + atom_datetime, atom_text, attr_value, decode, default_fixed_datetime, skip, FixedDateTime, +}; /// Represents an Atom feed #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -97,9 +98,9 @@ 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 decode(element.name().as_ref(), &reader)? == "feed" { return Feed::from_xml(&mut reader, element.attributes()); } else { return Err(Error::InvalidStartTag); @@ -132,10 +133,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()) @@ -680,66 +681,64 @@ impl FromXml for Feed { let mut feed = Feed::default(); let mut buf = Vec::new(); - for attr in atts.with_checks(false).flatten() { - match attr.key { - b"xml:base" => { - feed.base = Some( - attr.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + for att in atts.with_checks(false).flatten() { + match decode(att.key.as_ref(), reader)? { + Cow::Borrowed("xml:base") => { + feed.base = Some(attr_value(&att, reader)?.to_string()) } - b"xml:lang" => { - feed.lang = Some( - attr.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + Cow::Borrowed("xml:lang") => { + feed.lang = Some(attr_value(&att, reader)?.to_string()) } - b"xmlns:dc" => {} - attr_key if attr_key.starts_with(b"xmlns:") => { - let ns = str::from_utf8(&attr_key[6..])?.to_string(); - let ns_url = attr - .unescape_and_decode_value(reader) - .map_err(XmlError::new)?; - feed.namespaces.insert(ns, ns_url); + Cow::Borrowed("xmlns:dc") => {} + key => { + if let Some(ns) = key.strip_prefix("xmlns:") { + feed.namespaces + .insert(ns.to_string(), attr_value(&att, reader)?.to_string()); + } } - _ => {} } } loop { - match reader.read_event(&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" => { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { + Event::Start(element) => match decode(element.name().as_ref(), reader)? { + Cow::Borrowed("title") => { + feed.title = Text::from_xml(reader, element.attributes())? + } + Cow::Borrowed("id") => feed.id = atom_text(reader)?.unwrap_or_default(), + Cow::Borrowed("updated") => { feed.updated = atom_datetime(reader)?.unwrap_or_else(default_fixed_datetime) } - b"author" => feed + Cow::Borrowed("author") => feed .authors .push(Person::from_xml(reader, element.attributes())?), - b"category" => feed - .categories - .push(Category::from_xml(reader, element.attributes())?), - b"contributor" => feed + Cow::Borrowed("category") => { + feed.categories.push(Category::from_xml(reader, &element)?); + skip(element.name(), reader)?; + } + Cow::Borrowed("contributor") => feed .contributors .push(Person::from_xml(reader, element.attributes())?), - b"generator" => { + Cow::Borrowed("generator") => { feed.generator = Some(Generator::from_xml(reader, element.attributes())?) } - b"icon" => feed.icon = atom_text(reader)?, - 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" => { + Cow::Borrowed("icon") => feed.icon = atom_text(reader)?, + Cow::Borrowed("link") => { + feed.links.push(Link::from_xml(reader, &element)?); + skip(element.name(), reader)?; + } + Cow::Borrowed("logo") => feed.logo = atom_text(reader)?, + Cow::Borrowed("rights") => { + feed.rights = Some(Text::from_xml(reader, element.attributes())?) + } + Cow::Borrowed("subtitle") => { feed.subtitle = Some(Text::from_xml(reader, element.attributes())?) } - b"entry" => feed + Cow::Borrowed("entry") => feed .entries .push(Entry::from_xml(reader, element.attributes())?), n => { - if let Some((ns, name)) = extension_name(element.name()) { + if let Some((ns, name)) = extension_name(n.as_ref()) { parse_extension( reader, element.attributes(), @@ -748,9 +747,7 @@ impl FromXml for Feed { &mut feed.extensions, )?; } else { - reader - .read_to_end(n, &mut Vec::new()) - .map_err(XmlError::new)?; + skip(element.name(), reader)?; } } }, @@ -768,8 +765,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 +784,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 +796,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 +822,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..60d68dd 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; @@ -8,7 +9,7 @@ use quick_xml::Writer; use crate::error::{Error, XmlError}; use crate::fromxml::FromXml; use crate::toxml::ToXml; -use crate::util::atom_text; +use crate::util::{atom_text, attr_value, decode}; /// Represents the generator of an Atom feed #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -138,18 +139,12 @@ impl FromXml for Generator { let mut generator = Generator::default(); for att in atts.with_checks(false).flatten() { - match att.key { - b"uri" => { - generator.uri = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + match decode(att.key.as_ref(), reader)? { + Cow::Borrowed("uri") => { + generator.uri = Some(attr_value(&att, reader)?.to_string()); } - b"version" => { - generator.version = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + Cow::Borrowed("version") => { + generator.version = Some(attr_value(&att, reader)?.to_string()); } _ => {} } @@ -163,8 +158,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 +173,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..c265861 100644 --- a/src/link.rs +++ b/src/link.rs @@ -1,13 +1,13 @@ +use std::borrow::Cow; use std::io::{BufRead, Write}; -use quick_xml::events::attributes::Attributes; use quick_xml::events::{BytesStart, Event}; use quick_xml::Reader; use quick_xml::Writer; use crate::error::{Error, XmlError}; -use crate::fromxml::FromXml; use crate::toxml::ToXml; +use crate::util::{attr_value, decode}; /// Represents a link in an Atom feed #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -243,40 +243,38 @@ impl Link { } } -impl FromXml for Link { - fn from_xml(reader: &mut Reader, atts: Attributes<'_>) -> Result { - fn from_xml_inner( - reader: &mut Reader, - mut atts: Attributes<'_>, - ) -> Result { - let mut link = Link::default(); +impl Link { + pub(crate) fn from_xml<'s, B: BufRead>( + reader: &mut Reader, + element: &'s BytesStart<'s>, + ) -> 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)?), - _ => {} + for att in element.attributes().with_checks(false).flatten() { + match decode(att.key.as_ref(), reader)? { + Cow::Borrowed("href") => link.href = attr_value(&att, reader)?.to_string(), + Cow::Borrowed("rel") => link.rel = attr_value(&att, reader)?.to_string(), + Cow::Borrowed("hreflang") => { + link.hreflang = Some(attr_value(&att, reader)?.to_string()) + } + Cow::Borrowed("type") => { + link.mime_type = Some(attr_value(&att, reader)?.to_string()) + } + Cow::Borrowed("title") => link.title = Some(attr_value(&att, reader)?.to_string()), + Cow::Borrowed("length") => { + link.length = Some(attr_value(&att, reader)?.to_string()) } + _ => {} } - - reader.read_to_end(b"link", &mut Vec::new())?; - - Ok(link) } - from_xml_inner(reader, atts) - .map_err(XmlError::new) - .map_err(Error::from) + + Ok(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..e2b3652 100644 --- a/src/person.rs +++ b/src/person.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; @@ -8,7 +9,7 @@ use quick_xml::Writer; use crate::error::{Error, XmlError}; use crate::fromxml::FromXml; use crate::toxml::{ToXmlNamed, WriterExt}; -use crate::util::atom_text; +use crate::util::{atom_text, decode, skip}; /// Represents a person in an Atom feed #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -135,14 +136,12 @@ impl FromXml for Person { let mut buf = Vec::new(); loop { - match reader.read_event(&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)?, + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { + Event::Start(element) => match decode(element.name().as_ref(), reader)? { + Cow::Borrowed("name") => person.name = atom_text(reader)?.unwrap_or_default(), + Cow::Borrowed("email") => person.email = atom_text(reader)?, + Cow::Borrowed("uri") => person.uri = atom_text(reader)?, + _ => skip(element.name(), reader)?, }, Event::End(_) => break, Event::Eof => return Err(Error::Eof), @@ -157,27 +156,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..470d052 100644 --- a/src/source.rs +++ b/src/source.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::io::{BufRead, Write}; use quick_xml::events::attributes::Attributes; @@ -13,7 +14,7 @@ use crate::link::Link; use crate::person::Person; use crate::text::Text; use crate::toxml::{ToXml, WriterExt}; -use crate::util::{atom_datetime, atom_text, default_fixed_datetime, FixedDateTime}; +use crate::util::{atom_datetime, atom_text, decode, default_fixed_datetime, skip, FixedDateTime}; /// Represents the source of an Atom entry #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -454,40 +455,44 @@ impl FromXml for Source { let mut buf = Vec::new(); loop { - match reader.read_event(&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" => { + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { + Event::Start(element) => match decode(element.name().as_ref(), reader)? { + Cow::Borrowed("id") => source.id = atom_text(reader)?.unwrap_or_default(), + Cow::Borrowed("title") => { + source.title = Text::from_xml(reader, element.attributes())? + } + Cow::Borrowed("updated") => { source.updated = atom_datetime(reader)?.unwrap_or_else(default_fixed_datetime) } - b"author" => source + Cow::Borrowed("author") => source .authors .push(Person::from_xml(reader, element.attributes())?), - b"category" => source - .categories - .push(Category::from_xml(reader, element.attributes())?), - b"contributor" => source + Cow::Borrowed("category") => { + source + .categories + .push(Category::from_xml(reader, &element)?); + skip(element.name(), reader)?; + } + Cow::Borrowed("contributor") => source .contributors .push(Person::from_xml(reader, element.attributes())?), - b"generator" => { + Cow::Borrowed("generator") => { source.generator = Some(Generator::from_xml(reader, element.attributes())?) } - b"icon" => source.icon = atom_text(reader)?, - b"link" => source - .links - .push(Link::from_xml(reader, element.attributes())?), - b"logo" => source.logo = atom_text(reader)?, - b"rights" => { + Cow::Borrowed("icon") => source.icon = atom_text(reader)?, + Cow::Borrowed("link") => { + source.links.push(Link::from_xml(reader, &element)?); + skip(element.name(), reader)?; + } + Cow::Borrowed("logo") => source.logo = atom_text(reader)?, + Cow::Borrowed("rights") => { source.rights = Some(Text::from_xml(reader, element.attributes())?) } - b"subtitle" => { + Cow::Borrowed("subtitle") => { source.subtitle = Some(Text::from_xml(reader, element.attributes())?) } - n => reader - .read_to_end(n, &mut Vec::new()) - .map_err(XmlError::new)?, + _ => skip(element.name(), reader)?, }, Event::End(_) => break, Event::Eof => return Err(Error::Eof), @@ -503,13 +508,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 +524,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..4f64ca2 100644 --- a/src/text.rs +++ b/src/text.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::cmp::PartialEq; use std::convert::{AsRef, From}; use std::io::{BufRead, Write}; @@ -12,7 +13,7 @@ use quick_xml::Writer; use crate::error::{Error, XmlError}; use crate::fromxml::FromXml; use crate::toxml::ToXmlNamed; -use crate::util::{atom_text, atom_xhtml}; +use crate::util::{atom_text, atom_xhtml, attr_value, decode}; #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -162,25 +163,14 @@ impl FromXml for Text { let mut text = Text::default(); for att in atts.with_checks(false).flatten() { - match att.key { - b"xml:base" => { - text.base = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) + match decode(att.key.as_ref(), reader)? { + Cow::Borrowed("xml:base") => { + text.base = Some(attr_value(&att, reader)?.to_string()) } - b"xml:lang" => { - text.lang = Some( - att.unescape_and_decode_value(reader) - .map_err(XmlError::new)?, - ) - } - b"type" => { - text.r#type = att - .unescape_and_decode_value(reader) - .map_err(XmlError::new)? - .parse()? + Cow::Borrowed("xml:lang") => { + text.lang = Some(attr_value(&att, reader)?.to_string()) } + Cow::Borrowed("type") => text.r#type = attr_value(&att, reader)?.parse()?, _ => {} } } @@ -198,13 +188,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 +207,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..f0d1422 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,10 +1,10 @@ -use std::io::BufRead; - -use quick_xml::events::Event; +use quick_xml::events::attributes::Attribute; use quick_xml::Reader; +use quick_xml::{events::Event, name::QName}; use crate::error::{Error, XmlError}; use std::str::FromStr; +use std::{borrow::Cow, io::BufRead}; /// Alias of `::chrono::DateTime<::chrono::FixedOffset>` pub type FixedDateTime = ::chrono::DateTime<::chrono::FixedOffset>; @@ -13,6 +13,31 @@ pub fn default_fixed_datetime() -> FixedDateTime { FixedDateTime::from_str("1970-01-01T00:00:00Z").unwrap() } +pub(crate) fn decode<'s, 'r, B: BufRead>( + bytes: &'s [u8], + reader: &'r Reader, +) -> Result, Error> { + let text = reader.decoder().decode(bytes).map_err(XmlError::new)?; + Ok(text) +} + +pub(crate) fn attr_value<'s, 'r, B: BufRead>( + attr: &'s Attribute<'s>, + reader: &'r Reader, +) -> Result, Error> { + let value = attr + .decode_and_unescape_value(reader) + .map_err(XmlError::new)?; + Ok(value) +} + +pub(crate) fn skip(end: QName<'_>, reader: &mut Reader) -> Result<(), Error> { + reader + .read_to_end_into(end, &mut Vec::new()) + .map_err(XmlError::new)?; + Ok(()) +} + fn non_empty(string: String) -> Option { if !string.is_empty() { Some(string) @@ -29,11 +54,14 @@ 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(decode(&start, reader)?.as_ref()); result.push('>'); } Event::End(end) => { @@ -42,24 +70,28 @@ 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(decode(&start, reader)?.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 +118,14 @@ 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(decode(&start, reader)?.as_ref()); result.push('>'); } Event::End(end) => { @@ -99,24 +134,27 @@ 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(decode(&start, reader)?.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(decode(&text, reader)?.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(""); @@ -156,14 +194,14 @@ mod test { 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" => { - return atom_text(&mut reader) - } - Event::Start(element) if element.name() == b"raw" => { - return atom_xhtml(&mut reader) + match reader.read_event_into(&mut buf).map_err(XmlError::new)? { + Event::Start(element) => { + return match decode(element.name().as_ref(), &reader)? { + Cow::Borrowed("text") => atom_text(&mut reader), + Cow::Borrowed("raw") => atom_xhtml(&mut reader), + _ => Err(Error::InvalidStartTag), + } } - Event::Start(_) => return Err(Error::InvalidStartTag), Event::Eof => return Err(Error::Eof), _ => {} }