diff --git a/Changelog.md b/Changelog.md index f1bf2801..7935c3f9 100644 --- a/Changelog.md +++ b/Changelog.md @@ -22,9 +22,13 @@ instruction between a and the root element in the file brokes deserialization of structs by returning `DeError::ExpectedStart` +- [#597]: Fixed incorrect processing of namespace scopes in `NsReader::read_to_end`. + The scope started by a start element was not ended after that call. + ### Misc Changes [#581]: https://github.com/tafia/quick-xml/pull/581 +[#597]: https://github.com/tafia/quick-xml/issues/597 [#601]: https://github.com/tafia/quick-xml/pull/601 [#603]: https://github.com/tafia/quick-xml/pull/603 [#606]: https://github.com/tafia/quick-xml/pull/606 diff --git a/src/events/mod.rs b/src/events/mod.rs index b5480dee..7a484aae 100644 --- a/src/events/mod.rs +++ b/src/events/mod.rs @@ -963,10 +963,10 @@ pub enum Event<'a> { Empty(BytesStart<'a>), /// Escaped character data between tags. Text(BytesText<'a>), - /// Comment ``. - Comment(BytesText<'a>), /// Unescaped character data stored in ``. CData(BytesCData<'a>), + /// Comment ``. + Comment(BytesText<'a>), /// XML declaration ``. Decl(BytesDecl<'a>), /// Processing instruction ``. diff --git a/src/reader/mod.rs b/src/reader/mod.rs index e88eeca9..9c52f338 100644 --- a/src/reader/mod.rs +++ b/src/reader/mod.rs @@ -245,7 +245,7 @@ macro_rules! read_until_open { $(.$await)? { // Return Text event with `bytes` content - Ok(Some(bytes)) => $self.parser.read_text(bytes).map(Ok), + Ok(Some(bytes)) => $self.parser.emit_text(bytes).map(Ok), Ok(None) => Ok(Ok(Event::Eof)), Err(e) => Err(e), } @@ -287,7 +287,7 @@ macro_rules! read_until_close { $(.$await)? { Ok(None) => Ok(Event::Eof), - Ok(Some((bang_type, bytes))) => $self.parser.read_bang(bang_type, bytes), + Ok(Some((bang_type, bytes))) => $self.parser.emit_bang(bang_type, bytes), Err(e) => Err(e), }, // ` Ok(Event::Eof), - Ok(Some(bytes)) => $self.parser.read_end(bytes), + Ok(Some(bytes)) => $self.parser.emit_end(bytes), Err(e) => Err(e), }, // ` Ok(Event::Eof), - Ok(Some(bytes)) => $self.parser.read_question_mark(bytes), + Ok(Some(bytes)) => $self.parser.emit_question_mark(bytes), Err(e) => Err(e), }, // `<...` - opening or self-closed tag @@ -314,7 +314,7 @@ macro_rules! read_until_close { $(.$await)? { Ok(None) => Ok(Event::Eof), - Ok(Some(bytes)) => $self.parser.read_start(bytes), + Ok(Some(bytes)) => $self.parser.emit_start(bytes), Err(e) => Err(e), }, Ok(None) => Ok(Event::Eof), diff --git a/src/reader/ns_reader.rs b/src/reader/ns_reader.rs index 09457f28..1470d14c 100644 --- a/src/reader/ns_reader.rs +++ b/src/reader/ns_reader.rs @@ -524,7 +524,11 @@ impl NsReader { pub fn read_to_end_into(&mut self, end: QName, buf: &mut Vec) -> Result { // According to the https://www.w3.org/TR/xml11/#dt-etag, end name should // match literally the start name. See `Self::check_end_names` documentation - self.reader.read_to_end_into(end, buf) + let result = self.reader.read_to_end_into(end, buf)?; + // read_to_end_into will consume closing tag. Because nobody can access to its + // content anymore, we directly pop namespace of the opening tag + self.ns_resolver.pop(&mut self.buffer); + Ok(result) } } @@ -760,7 +764,11 @@ impl<'i> NsReader<&'i [u8]> { pub fn read_to_end(&mut self, end: QName) -> Result { // According to the https://www.w3.org/TR/xml11/#dt-etag, end name should // match literally the start name. See `Self::check_end_names` documentation - self.reader.read_to_end(end) + let result = self.reader.read_to_end(end)?; + // read_to_end will consume closing tag. Because nobody can access to its + // content anymore, we directly pop namespace of the opening tag + self.ns_resolver.pop(&mut self.buffer); + Ok(result) } /// Reads content between start and end tags, including any markup. This @@ -830,7 +838,13 @@ impl<'i> NsReader<&'i [u8]> { /// [`decoder()`]: Reader::decoder() #[inline] pub fn read_text(&mut self, end: QName) -> Result> { - self.reader.read_text(end) + // According to the https://www.w3.org/TR/xml11/#dt-etag, end name should + // match literally the start name. See `Self::check_end_names` documentation + let result = self.reader.read_text(end)?; + // read_text will consume closing tag. Because nobody can access to its + // content anymore, we directly pop namespace of the opening tag + self.ns_resolver.pop(&mut self.buffer); + Ok(result) } } @@ -842,3 +856,921 @@ impl Deref for NsReader { &self.reader } } + +#[cfg(test)] +mod read_to_end { + use super::*; + use crate::events::{BytesCData, BytesDecl, BytesEnd, BytesStart, BytesText}; + use crate::name::Namespace; + use pretty_assertions::assert_eq; + use ResolveResult::*; + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn decl() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Decl(BytesDecl::new("1.0", None, None)) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 45..52 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn doctype() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::DocType(BytesText::new("dtd")) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 38..45 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn pi() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::PI(BytesText::new("pi")) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn comment() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Comment(BytesText::new("comment")) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 38..45 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn start() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + reader.check_end_names(false); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 29..36 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn end() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + reader.check_end_names(false); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::End(BytesEnd::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn empty() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Empty(BytesStart::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn text() { + let mut reader = NsReader::from_str( + "\ + \ + text\ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Text(BytesText::new("text")) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 28..35 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn cdata() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::CData(BytesCData::new("cdata")) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 41..48 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } +} + +#[cfg(test)] +mod read_to_end_into { + use super::*; + use crate::events::{BytesCData, BytesDecl, BytesEnd, BytesStart, BytesText}; + use crate::name::Namespace; + use pretty_assertions::assert_eq; + use ResolveResult::*; + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn decl() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::Decl(BytesDecl::new("1.0", None, None)) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 45..52 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn doctype() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::DocType(BytesText::new("dtd")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 38..45 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn pi() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::PI(BytesText::new("pi")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn comment() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::Comment(BytesText::new("comment")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 38..45 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn start() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + reader.check_end_names(false); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 29..36 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn end() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + reader.check_end_names(false); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::End(BytesEnd::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn empty() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Empty(BytesStart::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn text() { + let mut reader = NsReader::from_str( + "\ + \ + text\ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::Text(BytesText::new("text")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 28..35 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn cdata() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::CData(BytesCData::new("cdata")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 41..48 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } +} + +#[cfg(test)] +mod read_text { + use super::*; + use crate::events::{BytesCData, BytesDecl, BytesEnd, BytesStart, BytesText}; + use crate::name::Namespace; + use pretty_assertions::assert_eq; + use ResolveResult::*; + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn decl() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Decl(BytesDecl::new("1.0", None, None)) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn doctype() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::DocType(BytesText::new("dtd")) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn pi() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::PI(BytesText::new("pi")) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn comment() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Comment(BytesText::new("comment")) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn start() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + reader.check_end_names(false); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::new("tag")), + ) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn end() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + reader.check_end_names(false); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::End(BytesEnd::new("tag")), + ) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn empty() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Empty(BytesStart::new("tag")), + ) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn text() { + let mut reader = NsReader::from_str( + "\ + \ + text\ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Text(BytesText::new("text")) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn cdata() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::CData(BytesCData::new("cdata")) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } +} diff --git a/src/reader/parser.rs b/src/reader/parser.rs index 1cb60867..5c33229e 100644 --- a/src/reader/parser.rs +++ b/src/reader/parser.rs @@ -65,7 +65,7 @@ impl Parser { /// - `bytes`: data from the start of stream to the first `<` or from `>` to `<` /// /// [`Text`]: Event::Text - pub fn read_text<'b>(&mut self, bytes: &'b [u8]) -> Result> { + pub fn emit_text<'b>(&mut self, bytes: &'b [u8]) -> Result> { let mut content = bytes; if self.trim_text_end { @@ -82,7 +82,7 @@ impl Parser { /// reads `BytesElement` starting with a `!`, /// return `Comment`, `CData` or `DocType` event - pub fn read_bang<'b>(&mut self, bang_type: BangType, buf: &'b [u8]) -> Result> { + pub fn emit_bang<'b>(&mut self, bang_type: BangType, buf: &'b [u8]) -> Result> { let uncased_starts_with = |string: &[u8], prefix: &[u8]| { string.len() >= prefix.len() && string[..prefix.len()].eq_ignore_ascii_case(prefix) }; @@ -129,7 +129,7 @@ impl Parser { /// Wraps content of `buf` into the [`Event::End`] event. Does the check that /// end name matches the last opened start name if `self.check_end_names` is set. - pub fn read_end<'b>(&mut self, buf: &'b [u8]) -> Result> { + pub fn emit_end<'b>(&mut self, buf: &'b [u8]) -> Result> { // XML standard permits whitespaces after the markup name in closing tags. // Let's strip them from the buffer before comparing tag names. let name = if self.trim_markup_names_in_closing_tags { @@ -180,7 +180,7 @@ impl Parser { /// reads `BytesElement` starting with a `?`, /// return `Decl` or `PI` event - pub fn read_question_mark<'b>(&mut self, buf: &'b [u8]) -> Result> { + pub fn emit_question_mark<'b>(&mut self, buf: &'b [u8]) -> Result> { let len = buf.len(); if len > 2 && buf[len - 1] == b'?' { if len > 5 && &buf[1..4] == b"xml" && is_whitespace(buf[4]) { @@ -208,7 +208,7 @@ impl Parser { /// /// # Parameters /// - `content`: Content of a tag between `<` and `>` - pub fn read_start<'b>(&mut self, content: &'b [u8]) -> Result> { + pub fn emit_start<'b>(&mut self, content: &'b [u8]) -> Result> { let len = content.len(); let name_end = content .iter() diff --git a/tests/issues.rs b/tests/issues.rs index a19355ba..af4c7269 100644 --- a/tests/issues.rs +++ b/tests/issues.rs @@ -5,8 +5,8 @@ use std::sync::mpsc; use quick_xml::events::{BytesStart, Event}; -use quick_xml::name::QName; -use quick_xml::reader::Reader; +use quick_xml::name::{Namespace, QName, ResolveResult}; +use quick_xml::reader::{NsReader, Reader}; use quick_xml::Error; /// Regression test for https://github.com/tafia/quick-xml/issues/115 @@ -105,3 +105,36 @@ mod issue514 { assert_eq!(reader.read_event().unwrap(), Event::Eof); } } + +#[test] +fn issue597() { + const S: &'static str = r#" + + + + + + + + + + "#; + + let mut reader = NsReader::from_str(S); + let objects_ns = loop { + let (ns, ev) = reader.read_resolved_event().unwrap(); + match ev { + Event::Start(v) if v.local_name().as_ref() == b"xmlfilecontent_test" => { + reader.read_to_end(v.name()).unwrap(); + } + Event::Empty(v) if v.local_name().as_ref() == b"objects" => break ns, + _ => (), + } + }; + assert_eq!( + objects_ns, + ResolveResult::Bound(Namespace( + b"http://oval.mitre.org/XMLSchema/oval-definitions-5" + )) + ); +}