use alloc::collections::{btree_map::Entry, BTreeMap};
use alloc::string::String;
#[cfg(not(feature = "extra-platforms"))]
use alloc::sync::Arc;
use alloc::vec::Vec;
#[cfg(feature = "extra-platforms")]
use portable_atomic_util::Arc;
use crate::context;
use crate::error::{add_context, EndOrError, Error, ErrorContext, Result};
use crate::strings::*;
use crate::xml_map::{AttrMap, Entry as AttrMapEntry};
use super::common::{EventMetrics, XmlVersion};
use super::raw::{RawEvent, RawQName};
pub type QName = (Namespace<'static>, NcName);
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Event {
XmlDeclaration(
EventMetrics,
XmlVersion,
),
StartElement(
EventMetrics,
QName,
AttrMap,
),
EndElement(
EventMetrics,
),
Text(
EventMetrics,
String,
),
}
impl Event {
pub fn metrics(&self) -> &EventMetrics {
match self {
Self::XmlDeclaration(m, ..) => m,
Self::StartElement(m, ..) => m,
Self::EndElement(m, ..) => m,
Self::Text(m, ..) => m,
}
}
}
#[derive(Debug)]
enum State {
Initial,
Element,
}
#[derive(Debug)]
struct ElementScratchpad {
phyqname: RawQName,
default_decl: Option<Namespace<'static>>,
nsdecl: BTreeMap<NcName, Namespace<'static>>,
}
impl ElementScratchpad {
fn new(phyqname: RawQName) -> Self {
Self {
phyqname,
default_decl: None,
nsdecl: BTreeMap::new(),
}
}
}
#[derive(Debug)]
pub struct NamespaceResolver {
ctx: Arc<context::Context>,
namespace_stack: Vec<(
Option<Namespace<'static>>,
BTreeMap<NcName, Namespace<'static>>,
)>,
scratchpad: Option<ElementScratchpad>,
phyattributes: Vec<(RawQName, String)>,
event_length_accum: usize,
state: State,
poison: Option<Error>,
}
impl NamespaceResolver {
pub fn new() -> Self {
Self::with_context(Arc::new(context::Context::new()))
}
pub fn with_context(ctx: Arc<context::Context>) -> Self {
Self {
ctx,
namespace_stack: Vec::new(),
phyattributes: Vec::new(),
scratchpad: None,
event_length_accum: 0,
state: State::Initial,
poison: None,
}
}
fn check_poison(&self) -> Result<()> {
if let Some(poison) = self.poison.as_ref() {
return Err(*poison);
}
Ok(())
}
fn start_element(&mut self, phyqn: RawQName) -> Result<()> {
debug_assert!(self.scratchpad.is_none());
debug_assert_eq!(self.phyattributes.len(), 0);
self.scratchpad = Some(ElementScratchpad::new(phyqn));
Ok(())
}
fn push_attribute(&mut self, phyqn: RawQName, value: String) -> Result<()> {
let scratchpad = self.scratchpad.as_mut().unwrap();
if let Some(prefix) = phyqn.0.as_ref() {
if prefix == "xmlns" {
match scratchpad.nsdecl.entry(phyqn.1) {
Entry::Occupied(_) => return Err(Error::DuplicateAttribute),
Entry::Vacant(e) => e.insert(self.ctx.intern_namespace(value)),
};
return Ok(());
}
} else if phyqn.1 == "xmlns" {
scratchpad.default_decl = Some(self.ctx.intern_namespace(value));
return Ok(());
}
self.phyattributes.push((phyqn, value));
Ok(())
}
fn lookup_prefix<'x>(
namespace_stack: &'x [(
Option<Namespace<'static>>,
BTreeMap<NcName, Namespace<'static>>,
)],
prefix: Option<&str>,
) -> Result<&'x Namespace<'static>> {
match prefix {
None => {
for (default_decl, _) in namespace_stack.iter().rev() {
if let Some(nsuri) = default_decl.as_ref() {
return Ok(nsuri);
}
}
Ok(Namespace::none())
}
Some(prefix) => {
if prefix == "xml" {
return Ok(Namespace::xml());
} else {
for (_, decls) in namespace_stack.iter().rev() {
if let Some(nsuri) = decls.get(prefix) {
return Ok(nsuri);
}
}
}
Err(Error::UndeclaredNamespacePrefix(None))
}
}
}
fn finish_element(&mut self) -> Result<Event> {
let ElementScratchpad {
phyqname,
default_decl,
nsdecl,
} = self.scratchpad.take().unwrap();
let len = self.event_length_accum;
self.event_length_accum = 0;
self.namespace_stack.push((default_decl, nsdecl));
let mut attributes = AttrMap::new();
for (phyqn, value) in self.phyattributes.drain(..) {
let nsuri = match phyqn.0 {
Some(prefix) => add_context(
Self::lookup_prefix(&self.namespace_stack, Some(&prefix)),
ErrorContext::AttributeName,
)?
.clone(),
None => Namespace::none().clone(),
};
match attributes.entry(nsuri, phyqn.1) {
AttrMapEntry::Occupied(_) => return Err(Error::DuplicateAttribute),
AttrMapEntry::Vacant(e) => e.insert(value),
};
}
let qname = (
add_context(
Self::lookup_prefix(
&self.namespace_stack,
phyqname.0.as_ref().map(|x| x.as_str()),
),
ErrorContext::Name,
)?
.clone(),
phyqname.1,
);
Ok(Event::StartElement(EventMetrics { len }, qname, attributes))
}
fn process_event(&mut self, ev: RawEvent) -> Result<Option<Event>> {
match ev {
RawEvent::ElementHeadOpen(_, phyqn) => match self.state {
State::Initial => {
self.state = State::Element;
self.start_element(phyqn)?;
Ok(None)
}
_ => unreachable!(),
},
RawEvent::Attribute(_, phyqn, value) => match self.state {
State::Element => {
self.push_attribute(phyqn, value)?;
Ok(None)
}
_ => unreachable!(),
},
RawEvent::ElementHeadClose(_) => match self.state {
State::Element => {
let ev = self.finish_element()?;
self.state = State::Initial;
Ok(Some(ev))
}
_ => unreachable!(),
},
RawEvent::ElementFoot(em) => {
self.event_length_accum = 0;
self.namespace_stack.pop();
Ok(Some(Event::EndElement(em)))
}
RawEvent::XmlDeclaration(em, v) => {
self.event_length_accum = 0;
Ok(Some(Event::XmlDeclaration(em, v)))
}
RawEvent::Text(em, v) => {
self.event_length_accum = 0;
Ok(Some(Event::Text(em, v)))
}
}
}
pub fn next<F: FnMut() -> core::result::Result<Option<RawEvent>, EndOrError>>(
&mut self,
mut f: F,
) -> core::result::Result<Option<Event>, EndOrError> {
self.check_poison()?;
loop {
let pev = match f() {
Ok(None) => return Ok(None),
Err(e) => return Err(e),
Ok(Some(pev)) => pev,
};
self.event_length_accum += pev.metrics().len();
match self.process_event(pev) {
Err(e) => {
self.poison = Some(e);
return Err(EndOrError::Error(e));
}
Ok(Some(v)) => return Ok(Some(v)),
Ok(None) => (),
}
}
}
pub fn context(&self) -> &Arc<context::Context> {
&self.ctx
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
const DM: EventMetrics = EventMetrics { len: 0 };
fn resolve_all(mut evs: Vec<RawEvent>) -> (Vec<Event>, core::result::Result<(), EndOrError>) {
let mut nsr = NamespaceResolver::new();
let mut out = Vec::new();
let mut iter = evs.drain(..);
loop {
match nsr.next(|| Ok(iter.next())) {
Err(err) => return (out, Err(err)),
Ok(Some(ev)) => out.push(ev),
Ok(None) => return (out, Ok(())),
}
}
}
#[test]
fn namespace_resolver_passes_xml_decl() {
let (evs, r) = resolve_all(vec![RawEvent::XmlDeclaration(
EventMetrics { len: 2342 },
XmlVersion::V1_0,
)]);
r.unwrap();
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::XmlDeclaration(em, v) => {
assert_eq!(em.len(), 2342);
assert_eq!(*v, XmlVersion::V1_0);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_aggregates_attributes_and_length() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(EventMetrics { len: 2 }, (None, "root".try_into().unwrap())),
RawEvent::Attribute(
EventMetrics { len: 3 },
(None, "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
EventMetrics { len: 4 },
(None, "a2".try_into().unwrap()),
"v2".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
]);
r.unwrap();
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 14);
assert!(nsuri.is_none());
assert_eq!(localpart, "root");
assert_eq!(attrs.get(Namespace::none(), "a1").unwrap(), "v1");
assert_eq!(attrs.get(Namespace::none(), "a2").unwrap(), "v2");
assert_eq!(attrs.len(), 2);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 6);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_passes_mixed_content() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(EventMetrics { len: 1 }, (None, "root".try_into().unwrap())),
RawEvent::ElementHeadClose(EventMetrics { len: 2 }),
RawEvent::Text(EventMetrics { len: 5 }, "Hello".try_into().unwrap()),
RawEvent::ElementHeadOpen(EventMetrics { len: 1 }, (None, "child".try_into().unwrap())),
RawEvent::ElementHeadClose(EventMetrics { len: 3 }),
RawEvent::Text(EventMetrics { len: 6 }, "mixed".try_into().unwrap()),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
RawEvent::Text(EventMetrics { len: 7 }, "world!".try_into().unwrap()),
RawEvent::ElementFoot(EventMetrics { len: 8 }),
]);
r.unwrap();
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 3);
assert!(nsuri.is_none());
assert_eq!(localpart, "root");
assert_eq!(attrs.len(), 0);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::Text(em, text) => {
assert_eq!(em.len(), 5);
assert_eq!(text, "Hello");
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 4);
assert!(nsuri.is_none());
assert_eq!(localpart, "child");
assert_eq!(attrs.len(), 0);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::Text(em, text) => {
assert_eq!(em.len(), 6);
assert_eq!(text, "mixed");
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 6);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::Text(em, text) => {
assert_eq!(em.len(), 7);
assert_eq!(text, "world!");
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 8);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_rejects_duplicate_attribute_name() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(EventMetrics { len: 2 }, (None, "root".try_into().unwrap())),
RawEvent::Attribute(
EventMetrics { len: 3 },
(None, "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
EventMetrics { len: 4 },
(None, "a1".try_into().unwrap()),
"v2".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
]);
match r {
Err(EndOrError::Error(Error::DuplicateAttribute)) => (),
other => panic!("unexpected result: {:?}", other),
}
let mut iter = evs.iter();
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_returns_error_forever() {
let pevs_invalid = vec![
RawEvent::ElementHeadOpen(EventMetrics { len: 2 }, (None, "root".try_into().unwrap())),
RawEvent::Attribute(
EventMetrics { len: 3 },
(None, "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
EventMetrics { len: 4 },
(None, "a1".try_into().unwrap()),
"v2".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
];
let pevs_valid = vec![
RawEvent::ElementHeadOpen(EventMetrics { len: 2 }, (None, "root".try_into().unwrap())),
RawEvent::Attribute(
EventMetrics { len: 3 },
(None, "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
];
let mut nsr = NamespaceResolver::new();
{
let mut iter = pevs_invalid.iter();
match nsr.next(|| Ok(iter.next().cloned())) {
Err(EndOrError::Error(Error::DuplicateAttribute)) => (),
other => panic!("unexpected result: {:?}", other),
}
}
{
let mut iter = pevs_valid.iter();
match nsr.next(|| Ok(iter.next().cloned())) {
Err(EndOrError::Error(Error::DuplicateAttribute)) => (),
other => panic!("unexpected result: {:?}", other),
}
}
}
#[test]
fn namespace_resolver_resolves_default_namespace_on_element() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(EventMetrics { len: 2 }, (None, "root".try_into().unwrap())),
RawEvent::Attribute(
EventMetrics { len: 3 },
(None, "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
EventMetrics { len: 4 },
(None, "xmlns".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
]);
r.unwrap();
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 14);
assert_eq!(nsuri, "foo");
assert_eq!(localpart, "root");
assert_eq!(attrs.get(Namespace::none(), "a1").unwrap(), "v1");
assert_eq!(attrs.len(), 1);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 6);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_resolves_prefixed_namespace_on_element() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(
EventMetrics { len: 2 },
(Some("foo".try_into().unwrap()), "root".try_into().unwrap()),
),
RawEvent::Attribute(
EventMetrics { len: 3 },
(None, "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
EventMetrics { len: 4 },
(Some("xmlns".try_into().unwrap()), "foo".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
]);
r.unwrap();
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 14);
assert_eq!(nsuri, "foo");
assert_eq!(localpart, "root");
assert_eq!(attrs.get(Namespace::none(), "a1").unwrap(), "v1");
assert_eq!(attrs.len(), 1);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 6);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_resolves_prefixed_namespace_on_attribute() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(EventMetrics { len: 2 }, (None, "root".try_into().unwrap())),
RawEvent::Attribute(
EventMetrics { len: 3 },
(Some("foo".try_into().unwrap()), "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
EventMetrics { len: 4 },
(Some("xmlns".try_into().unwrap()), "foo".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
]);
r.unwrap();
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 14);
assert!(nsuri.is_none());
assert_eq!(localpart, "root");
assert_eq!(attrs.get("foo", "a1").unwrap(), "v1");
assert_eq!(attrs.len(), 1);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 6);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_resolves_prefixed_namespace_on_nested_elements() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(
EventMetrics { len: 2 },
(Some("x".try_into().unwrap()), "root".try_into().unwrap()),
),
RawEvent::Attribute(
EventMetrics { len: 3 },
(None, "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
EventMetrics { len: 4 },
(Some("xmlns".try_into().unwrap()), "x".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementHeadOpen(
EventMetrics { len: 1 },
(Some("x".try_into().unwrap()), "child".try_into().unwrap()),
),
RawEvent::Attribute(
EventMetrics { len: 3 },
(Some("x".try_into().unwrap()), "a2".try_into().unwrap()),
"v2".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 2 }),
RawEvent::ElementFoot(EventMetrics { len: 4 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
]);
r.unwrap();
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 14);
assert_eq!(nsuri, "foo");
assert_eq!(localpart, "root");
assert_eq!(attrs.get(Namespace::none(), "a1").unwrap(), "v1");
assert_eq!(attrs.len(), 1);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 6);
assert_eq!(nsuri, "foo");
assert_eq!(localpart, "child");
assert_eq!(attrs.get("foo", "a2").unwrap(), "v2");
assert_eq!(attrs.len(), 1);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 4);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 6);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_rejects_undeclared_prefix_in_element_name() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(
EventMetrics { len: 2 },
(Some("x".try_into().unwrap()), "root".try_into().unwrap()),
),
RawEvent::Attribute(
EventMetrics { len: 3 },
(None, "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
EventMetrics { len: 4 },
(Some("xmlns".try_into().unwrap()), "x".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementHeadOpen(
EventMetrics { len: 1 },
(Some("foo".try_into().unwrap()), "child".try_into().unwrap()),
),
RawEvent::ElementHeadClose(EventMetrics { len: 2 }),
RawEvent::ElementFoot(EventMetrics { len: 4 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
]);
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 14);
assert_eq!(nsuri, "foo");
assert_eq!(localpart, "root");
assert_eq!(attrs.get(Namespace::none(), "a1").unwrap(), "v1");
assert_eq!(attrs.len(), 1);
}
other => panic!("unexpected event: {:?}", other),
}
match r {
Err(EndOrError::Error(Error::UndeclaredNamespacePrefix(Some(ErrorContext::Name)))) => {
()
}
other => panic!("unexpected result: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_rejects_undeclared_prefix_in_attribute_name() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(
EventMetrics { len: 2 },
(Some("x".try_into().unwrap()), "root".try_into().unwrap()),
),
RawEvent::Attribute(
EventMetrics { len: 3 },
(None, "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
EventMetrics { len: 4 },
(Some("xmlns".try_into().unwrap()), "x".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 5 }),
RawEvent::ElementHeadOpen(
EventMetrics { len: 1 },
(Some("x".try_into().unwrap()), "child".try_into().unwrap()),
),
RawEvent::Attribute(
EventMetrics { len: 3 },
(Some("foo".try_into().unwrap()), "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 2 }),
RawEvent::ElementFoot(EventMetrics { len: 4 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
]);
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(em, (nsuri, localpart), attrs) => {
assert_eq!(em.len(), 14);
assert_eq!(nsuri, "foo");
assert_eq!(localpart, "root");
assert_eq!(attrs.get(Namespace::none(), "a1").unwrap(), "v1");
assert_eq!(attrs.len(), 1);
}
other => panic!("unexpected event: {:?}", other),
}
match r {
Err(EndOrError::Error(Error::UndeclaredNamespacePrefix(Some(
ErrorContext::AttributeName,
)))) => (),
other => panic!("unexpected result: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_rejects_duplicate_attribute_post_namespace_resolution() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(DM, (None, "root".try_into().unwrap())),
RawEvent::Attribute(
DM,
(Some("xmlns".try_into().unwrap()), "x".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::Attribute(
DM,
(Some("xmlns".try_into().unwrap()), "y".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::ElementHeadClose(DM),
RawEvent::ElementHeadOpen(DM, (None, "child".try_into().unwrap())),
RawEvent::Attribute(
DM,
(Some("x".try_into().unwrap()), "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
DM,
(Some("y".try_into().unwrap()), "a1".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::ElementHeadClose(DM),
RawEvent::ElementFoot(DM),
RawEvent::ElementFoot(DM),
]);
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(_, (nsuri, localpart), attrs) => {
assert!(nsuri.is_none());
assert_eq!(localpart, "root");
assert_eq!(attrs.len(), 0);
}
other => panic!("unexpected event: {:?}", other),
}
match r {
Err(EndOrError::Error(Error::DuplicateAttribute)) => (),
other => panic!("unexpected result: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_rejects_namespace_redeclaration_within_the_same_header() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(DM, (None, "root".try_into().unwrap())),
RawEvent::Attribute(
DM,
(Some("xmlns".try_into().unwrap()), "x".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::Attribute(
DM,
(Some("xmlns".try_into().unwrap()), "x".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::ElementHeadClose(DM),
RawEvent::ElementFoot(DM),
]);
let mut iter = evs.iter();
match r {
Err(EndOrError::Error(Error::DuplicateAttribute)) => (),
other => panic!("unexpected result: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn namespace_resolver_with_multiple_prefixes_and_rebinding() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(
DM,
(Some("x".try_into().unwrap()), "root".try_into().unwrap()),
),
RawEvent::Attribute(
DM,
(Some("xmlns".try_into().unwrap()), "x".try_into().unwrap()),
"foo".try_into().unwrap(),
),
RawEvent::Attribute(
DM,
(Some("xmlns".try_into().unwrap()), "y".try_into().unwrap()),
"bar".try_into().unwrap(),
),
RawEvent::Attribute(
DM,
(Some("x".try_into().unwrap()), "a".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
DM,
(Some("y".try_into().unwrap()), "a".try_into().unwrap()),
"v2".try_into().unwrap(),
),
RawEvent::ElementHeadClose(DM),
RawEvent::ElementHeadOpen(
DM,
(Some("y".try_into().unwrap()), "child".try_into().unwrap()),
),
RawEvent::Attribute(
DM,
(Some("x".try_into().unwrap()), "a".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::Attribute(
DM,
(Some("y".try_into().unwrap()), "a".try_into().unwrap()),
"v2".try_into().unwrap(),
),
RawEvent::Attribute(
DM,
(Some("xmlns".try_into().unwrap()), "y".try_into().unwrap()),
"baz".try_into().unwrap(),
),
RawEvent::ElementHeadClose(DM),
RawEvent::ElementFoot(DM),
RawEvent::ElementFoot(DM),
]);
r.unwrap();
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(_, (nsuri, localpart), attrs) => {
assert_eq!(nsuri, "foo");
assert_eq!(localpart, "root");
assert_eq!(attrs.get("foo", "a").unwrap(), "v1");
assert_eq!(attrs.get("bar", "a").unwrap(), "v2");
assert_eq!(attrs.len(), 2);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::StartElement(_, (nsuri, localpart), attrs) => {
assert_eq!(nsuri, "baz");
assert_eq!(localpart, "child");
assert_eq!(attrs.get("foo", "a").unwrap(), "v1");
assert_eq!(attrs.get("baz", "a").unwrap(), "v2");
assert_eq!(attrs.len(), 2);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(_) => (),
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(_) => (),
other => panic!("unexpected event: {:?}", other),
}
match iter.next() {
None => (),
other => panic!("unexpected event: {:?}", other),
}
}
#[test]
fn parser_correctly_accounts_lengths() {
let (evs, r) = resolve_all(vec![
RawEvent::ElementHeadOpen(EventMetrics { len: 5 }, (None, "foo".try_into().unwrap())),
RawEvent::Attribute(
EventMetrics { len: 7 },
(None, "a".try_into().unwrap()),
"v1".try_into().unwrap(),
),
RawEvent::ElementHeadClose(EventMetrics { len: 1 }),
RawEvent::ElementHeadOpen(EventMetrics { len: 3 }, (None, "n1".try_into().unwrap())),
RawEvent::ElementHeadClose(EventMetrics { len: 1 }),
RawEvent::ElementHeadOpen(EventMetrics { len: 3 }, (None, "n2".try_into().unwrap())),
RawEvent::ElementHeadClose(EventMetrics { len: 1 }),
RawEvent::ElementHeadOpen(EventMetrics { len: 3 }, (None, "n3".try_into().unwrap())),
RawEvent::ElementHeadClose(EventMetrics { len: 2 }),
RawEvent::ElementFoot(EventMetrics { len: 0 }),
RawEvent::ElementFoot(EventMetrics { len: 5 }),
RawEvent::ElementHeadOpen(EventMetrics { len: 3 }, (None, "n2".try_into().unwrap())),
RawEvent::ElementHeadClose(EventMetrics { len: 1 }),
RawEvent::Text(EventMetrics { len: 3 }, "foo".try_into().unwrap()),
RawEvent::ElementFoot(EventMetrics { len: 5 }),
RawEvent::ElementFoot(EventMetrics { len: 5 }),
RawEvent::ElementFoot(EventMetrics { len: 6 }),
]);
r.unwrap();
let mut iter = evs.iter();
match iter.next().unwrap() {
Event::StartElement(em, (_, name), _) if name == "foo" => {
assert_eq!(em.len(), 13);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::StartElement(em, (_, name), _) if name == "n1" => {
assert_eq!(em.len(), 4);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::StartElement(em, (_, name), _) if name == "n2" => {
assert_eq!(em.len(), 4);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::StartElement(em, (_, name), _) if name == "n3" => {
assert_eq!(em.len(), 5);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 0);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 5);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::StartElement(em, (_, name), _) if name == "n2" => {
assert_eq!(em.len(), 4);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::Text(em, text) if text == "foo" => {
assert_eq!(em.len(), 3);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 5);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 5);
}
other => panic!("unexpected event: {:?}", other),
}
match iter.next().unwrap() {
Event::EndElement(em) => {
assert_eq!(em.len(), 6);
}
other => panic!("unexpected event: {:?}", other),
}
}
}