use crate::events::attributes::Attribute;
use crate::events::{BytesStart, Event};
use crate::utils::{write_byte_string, Bytes};
use memchr::memchr;
use std::fmt::{self, Debug, Formatter};
use std::iter::FusedIterator;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NamespaceError {
UnknownPrefix(Vec<u8>),
InvalidXmlPrefixBind(Vec<u8>),
InvalidXmlnsPrefixBind(Vec<u8>),
InvalidPrefixForXml(Vec<u8>),
InvalidPrefixForXmlns(Vec<u8>),
}
impl fmt::Display for NamespaceError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::UnknownPrefix(prefix) => {
f.write_str("unknown namespace prefix '")?;
write_byte_string(f, prefix)?;
f.write_str("'")
}
Self::InvalidXmlPrefixBind(namespace) => {
f.write_str("the namespace prefix 'xml' cannot be bound to '")?;
write_byte_string(f, namespace)?;
f.write_str("'")
}
Self::InvalidXmlnsPrefixBind(namespace) => {
f.write_str("the namespace prefix 'xmlns' cannot be bound to '")?;
write_byte_string(f, namespace)?;
f.write_str("'")
}
Self::InvalidPrefixForXml(prefix) => {
f.write_str("the namespace prefix '")?;
write_byte_string(f, prefix)?;
f.write_str("' cannot be bound to 'http://www.w3.org/XML/1998/namespace'")
}
Self::InvalidPrefixForXmlns(prefix) => {
f.write_str("the namespace prefix '")?;
write_byte_string(f, prefix)?;
f.write_str("' cannot be bound to 'http://www.w3.org/2000/xmlns/'")
}
}
}
}
impl std::error::Error for NamespaceError {}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct QName<'a>(pub &'a [u8]);
impl<'a> QName<'a> {
#[inline(always)]
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
pub fn local_name(&self) -> LocalName<'a> {
LocalName(self.index().map_or(self.0, |i| &self.0[i + 1..]))
}
pub fn prefix(&self) -> Option<Prefix<'a>> {
self.index().map(|i| Prefix(&self.0[..i]))
}
pub fn decompose(&self) -> (LocalName<'a>, Option<Prefix<'a>>) {
match self.index() {
None => (LocalName(self.0), None),
Some(i) => (LocalName(&self.0[i + 1..]), Some(Prefix(&self.0[..i]))),
}
}
pub fn as_namespace_binding(&self) -> Option<PrefixDeclaration<'a>> {
if self.0.starts_with(b"xmlns") {
return match self.0.get(5) {
None => Some(PrefixDeclaration::Default),
Some(&b':') => Some(PrefixDeclaration::Named(&self.0[6..])),
_ => None,
};
}
None
}
#[inline(always)]
fn index(&self) -> Option<usize> {
memchr(b':', self.0)
}
}
impl<'a> Debug for QName<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "QName(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for QName<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct LocalName<'a>(pub(crate) &'a [u8]);
impl<'a> LocalName<'a> {
#[inline(always)]
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
}
impl<'a> Debug for LocalName<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "LocalName(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for LocalName<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
impl<'a> From<QName<'a>> for LocalName<'a> {
#[inline]
fn from(name: QName<'a>) -> Self {
Self(name.index().map_or(name.0, |i| &name.0[i + 1..]))
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct Prefix<'a>(&'a [u8]);
impl<'a> Prefix<'a> {
#[inline(always)]
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
#[inline(always)]
pub const fn is_xml(&self) -> bool {
matches!(self.0, b"xml")
}
#[inline(always)]
pub const fn is_xmlns(&self) -> bool {
matches!(self.0, b"xmlns")
}
}
impl<'a> Debug for Prefix<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Prefix(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for Prefix<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PrefixDeclaration<'a> {
Default,
Named(&'a [u8]),
}
impl<'a> Debug for PrefixDeclaration<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Default => f.write_str("PrefixDeclaration::Default"),
Self::Named(prefix) => {
f.write_str("PrefixDeclaration::Named(")?;
write_byte_string(f, prefix)?;
f.write_str(")")
}
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct Namespace<'a>(pub &'a [u8]);
impl<'a> Namespace<'a> {
#[inline(always)]
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
}
impl<'a> Debug for Namespace<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Namespace(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for Namespace<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum ResolveResult<'ns> {
Unbound,
Bound(Namespace<'ns>),
Unknown(Vec<u8>),
}
impl<'ns> Debug for ResolveResult<'ns> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Unbound => write!(f, "Unbound"),
Self::Bound(ns) => write!(f, "Bound({:?})", ns),
Self::Unknown(p) => {
write!(f, "Unknown(")?;
write_byte_string(f, p)?;
write!(f, ")")
}
}
}
}
impl<'ns> TryFrom<ResolveResult<'ns>> for Option<Namespace<'ns>> {
type Error = NamespaceError;
fn try_from(result: ResolveResult<'ns>) -> Result<Self, NamespaceError> {
use ResolveResult::*;
match result {
Unbound => Ok(None),
Bound(ns) => Ok(Some(ns)),
Unknown(p) => Err(NamespaceError::UnknownPrefix(p)),
}
}
}
#[derive(Debug, Clone)]
struct NamespaceBinding {
start: usize,
prefix_len: usize,
value_len: usize,
level: u16,
}
impl NamespaceBinding {
#[inline]
fn prefix<'b>(&self, ns_buffer: &'b [u8]) -> Option<Prefix<'b>> {
if self.prefix_len == 0 {
None
} else {
Some(Prefix(&ns_buffer[self.start..self.start + self.prefix_len]))
}
}
#[inline]
fn namespace<'ns>(&self, buffer: &'ns [u8]) -> ResolveResult<'ns> {
if self.value_len == 0 {
ResolveResult::Unbound
} else {
let start = self.start + self.prefix_len;
ResolveResult::Bound(Namespace(&buffer[start..start + self.value_len]))
}
}
}
#[derive(Clone)]
pub struct NamespaceResolver {
buffer: Vec<u8>,
bindings: Vec<NamespaceBinding>,
nesting_level: u16,
}
impl Debug for NamespaceResolver {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("NamespaceResolver")
.field("buffer", &Bytes(&self.buffer))
.field("bindings", &self.bindings)
.field("nesting_level", &self.nesting_level)
.finish()
}
}
const RESERVED_NAMESPACE_XML: (Prefix, Namespace) = (
Prefix(b"xml"),
Namespace(b"http://www.w3.org/XML/1998/namespace"),
);
const RESERVED_NAMESPACE_XMLNS: (Prefix, Namespace) = (
Prefix(b"xmlns"),
Namespace(b"http://www.w3.org/2000/xmlns/"),
);
impl Default for NamespaceResolver {
fn default() -> Self {
let mut buffer = Vec::new();
let mut bindings = Vec::new();
for ent in &[RESERVED_NAMESPACE_XML, RESERVED_NAMESPACE_XMLNS] {
let prefix = ent.0.into_inner();
let uri = ent.1.into_inner();
bindings.push(NamespaceBinding {
start: buffer.len(),
prefix_len: prefix.len(),
value_len: uri.len(),
level: 0,
});
buffer.extend(prefix);
buffer.extend(uri);
}
Self {
buffer,
bindings,
nesting_level: 0,
}
}
}
impl NamespaceResolver {
pub fn add(
&mut self,
prefix: PrefixDeclaration,
namespace: Namespace,
) -> Result<(), NamespaceError> {
let level = self.nesting_level;
match prefix {
PrefixDeclaration::Default => {
let start = self.buffer.len();
self.buffer.extend_from_slice(namespace.0);
self.bindings.push(NamespaceBinding {
start,
prefix_len: 0,
value_len: namespace.0.len(),
level,
});
}
PrefixDeclaration::Named(b"xml") => {
if namespace != RESERVED_NAMESPACE_XML.1 {
return Err(NamespaceError::InvalidXmlPrefixBind(namespace.0.to_vec()));
}
}
PrefixDeclaration::Named(b"xmlns") => {
return Err(NamespaceError::InvalidXmlnsPrefixBind(namespace.0.to_vec()));
}
PrefixDeclaration::Named(prefix) => {
if namespace == RESERVED_NAMESPACE_XML.1 {
return Err(NamespaceError::InvalidPrefixForXml(prefix.to_vec()));
} else
if namespace == RESERVED_NAMESPACE_XMLNS.1 {
return Err(NamespaceError::InvalidPrefixForXmlns(prefix.to_vec()));
}
let start = self.buffer.len();
self.buffer.extend_from_slice(prefix);
self.buffer.extend_from_slice(namespace.0);
self.bindings.push(NamespaceBinding {
start,
prefix_len: prefix.len(),
value_len: namespace.0.len(),
level,
});
}
}
Ok(())
}
pub fn push(&mut self, start: &BytesStart) -> Result<(), NamespaceError> {
self.nesting_level += 1;
for a in start.attributes().with_checks(false) {
if let Ok(Attribute { key: k, value: v }) = a {
if let Some(prefix) = k.as_namespace_binding() {
self.add(prefix, Namespace(&v))?;
}
} else {
break;
}
}
Ok(())
}
#[inline]
pub fn pop(&mut self) {
self.set_level(self.nesting_level.saturating_sub(1));
}
pub fn set_level(&mut self, level: u16) {
self.nesting_level = level;
match self.bindings.iter().rposition(|n| n.level <= level) {
None => {
self.buffer.clear();
self.bindings.clear();
}
Some(last_valid_pos) => {
if let Some(len) = self.bindings.get(last_valid_pos + 1).map(|n| n.start) {
self.buffer.truncate(len);
self.bindings.truncate(last_valid_pos + 1);
}
}
}
}
#[inline]
pub fn resolve<'n>(
&self,
name: QName<'n>,
use_default: bool,
) -> (ResolveResult<'_>, LocalName<'n>) {
let (local_name, prefix) = name.decompose();
(self.resolve_prefix(prefix, use_default), local_name)
}
#[inline]
pub fn resolve_element<'n>(&self, name: QName<'n>) -> (ResolveResult<'_>, LocalName<'n>) {
self.resolve(name, true)
}
#[inline]
pub fn resolve_attribute<'n>(&self, name: QName<'n>) -> (ResolveResult<'_>, LocalName<'n>) {
self.resolve(name, false)
}
pub fn resolve_event<'i>(&self, event: Event<'i>) -> (ResolveResult<'_>, Event<'i>) {
use Event::*;
match event {
Empty(e) => (self.resolve_prefix(e.name().prefix(), true), Empty(e)),
Start(e) => (self.resolve_prefix(e.name().prefix(), true), Start(e)),
End(e) => (self.resolve_prefix(e.name().prefix(), true), End(e)),
e => (ResolveResult::Unbound, e),
}
}
pub fn resolve_prefix(&self, prefix: Option<Prefix>, use_default: bool) -> ResolveResult<'_> {
let mut iter = self.bindings.iter().rev();
match (prefix, use_default) {
(None, false) => ResolveResult::Unbound,
(None, true) => match iter.find(|n| n.prefix_len == 0) {
Some(n) => n.namespace(&self.buffer),
None => ResolveResult::Unbound,
},
(Some(p), _) => match iter.find(|n| n.prefix(&self.buffer) == prefix) {
Some(n) if n.value_len != 0 => n.namespace(&self.buffer),
_ => ResolveResult::Unknown(p.into_inner().to_vec()),
},
}
}
#[inline]
pub const fn bindings(&self) -> NamespaceBindingsIter<'_> {
NamespaceBindingsIter {
resolver: self,
cursor: 2,
}
}
pub const fn bindings_of(&self, level: u16) -> NamespaceBindingsOfLevelIter<'_> {
NamespaceBindingsOfLevelIter {
resolver: self,
cursor: 0,
level,
}
}
pub const fn level(&self) -> u16 {
self.nesting_level
}
}
#[derive(Debug, Clone)]
pub struct NamespaceBindingsIter<'a> {
resolver: &'a NamespaceResolver,
cursor: usize,
}
impl<'a> Iterator for NamespaceBindingsIter<'a> {
type Item = (PrefixDeclaration<'a>, Namespace<'a>);
fn next(&mut self) -> Option<(PrefixDeclaration<'a>, Namespace<'a>)> {
while let Some(binding) = self.resolver.bindings.get(self.cursor) {
self.cursor += 1;
let prefix = binding.prefix(&self.resolver.buffer);
if self.resolver.bindings[self.cursor..]
.iter()
.any(|ne| prefix == ne.prefix(&self.resolver.buffer))
{
continue; }
if let ResolveResult::Bound(namespace) = binding.namespace(&self.resolver.buffer) {
let prefix = match prefix {
Some(Prefix(prefix)) => PrefixDeclaration::Named(prefix),
None => PrefixDeclaration::Default,
};
return Some((prefix, namespace));
}
}
None }
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.resolver.bindings.len() - self.cursor))
}
}
impl<'a> FusedIterator for NamespaceBindingsIter<'a> {}
#[deprecated = "Use NamespaceBindingsIter instead. This alias will be removed in 0.40.0"]
pub type PrefixIter<'a> = NamespaceBindingsIter<'a>;
#[derive(Debug, Clone)]
pub struct NamespaceBindingsOfLevelIter<'a> {
resolver: &'a NamespaceResolver,
cursor: usize,
level: u16,
}
impl<'a> Iterator for NamespaceBindingsOfLevelIter<'a> {
type Item = (PrefixDeclaration<'a>, Namespace<'a>);
fn next(&mut self) -> Option<(PrefixDeclaration<'a>, Namespace<'a>)> {
while let Some(binding) = self.resolver.bindings.get(self.cursor) {
self.cursor += 1; if binding.level < self.level {
continue;
}
if binding.level > self.level {
break;
}
if let ResolveResult::Bound(namespace) = binding.namespace(&self.resolver.buffer) {
let prefix = match binding.prefix(&self.resolver.buffer) {
Some(Prefix(prefix)) => PrefixDeclaration::Named(prefix),
None => PrefixDeclaration::Default,
};
return Some((prefix, namespace));
}
}
None }
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.resolver.bindings.len() - self.cursor))
}
}
impl<'a> FusedIterator for NamespaceBindingsOfLevelIter<'a> {}
#[cfg(test)]
mod namespaces {
use super::*;
use pretty_assertions::assert_eq;
use ResolveResult::*;
mod unprefixed {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn basic() {
let name = QName(b"simple");
let ns = Namespace(b"default");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns='default'", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"default");
resolver.push(&BytesStart::from_content("", 0)).unwrap();
assert_eq!(&resolver.buffer[s..], b"default");
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"default");
assert_eq!(
resolver.resolve(name, true),
(Bound(ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
}
#[test]
fn override_namespace() {
let name = QName(b"simple");
let old_ns = Namespace(b"old");
let new_ns = Namespace(b"new");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns='old'", 0))
.unwrap();
resolver
.push(&BytesStart::from_content(" xmlns='new'", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"oldnew");
assert_eq!(
resolver.resolve(name, true),
(Bound(new_ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"old");
assert_eq!(
resolver.resolve(name, true),
(Bound(old_ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
}
#[test]
fn reset() {
let name = QName(b"simple");
let old_ns = Namespace(b"old");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns='old'", 0))
.unwrap();
resolver
.push(&BytesStart::from_content(" xmlns=''", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"old");
assert_eq!(
resolver.resolve(name, true),
(Unbound, LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"old");
assert_eq!(
resolver.resolve(name, true),
(Bound(old_ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
}
}
mod declared_prefix {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn basic() {
let name = QName(b"p:with-declared-prefix");
let ns = Namespace(b"default");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns:p='default'", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"pdefault");
resolver.push(&BytesStart::from_content("", 0)).unwrap();
assert_eq!(&resolver.buffer[s..], b"pdefault");
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"pdefault");
assert_eq!(
resolver.resolve(name, true),
(Bound(ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(ns), LocalName(b"with-declared-prefix"))
);
}
#[test]
fn override_namespace() {
let name = QName(b"p:with-declared-prefix");
let old_ns = Namespace(b"old");
let new_ns = Namespace(b"new");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns:p='old'", 0))
.unwrap();
resolver
.push(&BytesStart::from_content(" xmlns:p='new'", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"poldpnew");
assert_eq!(
resolver.resolve(name, true),
(Bound(new_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(new_ns), LocalName(b"with-declared-prefix"))
);
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"pold");
assert_eq!(
resolver.resolve(name, true),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
}
#[test]
fn reset() {
let name = QName(b"p:with-declared-prefix");
let old_ns = Namespace(b"old");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns:p='old'", 0))
.unwrap();
resolver
.push(&BytesStart::from_content(" xmlns:p=''", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"poldp");
assert_eq!(
resolver.resolve(name, true),
(Unknown(b"p".to_vec()), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Unknown(b"p".to_vec()), LocalName(b"with-declared-prefix"))
);
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"pold");
assert_eq!(
resolver.resolve(name, true),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
}
}
mod builtin_prefixes {
use super::*;
mod xml {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn undeclared() {
let name = QName(b"xml:random");
let namespace = RESERVED_NAMESPACE_XML.1;
let resolver = NamespaceResolver::default();
assert_eq!(
resolver.resolve(name, true),
(Bound(namespace), LocalName(b"random"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(namespace), LocalName(b"random"))
);
}
#[test]
fn rebound_to_correct_ns() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver.push(
&BytesStart::from_content(
" xmlns:xml='http://www.w3.org/XML/1998/namespace'",
0,
),
).expect("`xml` prefix should be possible to bound to `http://www.w3.org/XML/1998/namespace`");
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn rebound_to_incorrect_ns() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
assert_eq!(
resolver.push(&BytesStart::from_content(
" xmlns:xml='not_correct_namespace'",
0,
)),
Err(NamespaceError::InvalidXmlPrefixBind(
b"not_correct_namespace".to_vec()
)),
);
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn unbound() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
assert_eq!(
resolver.push(&BytesStart::from_content(" xmlns:xml=''", 0)),
Err(NamespaceError::InvalidXmlPrefixBind(b"".to_vec())),
);
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn other_prefix_bound_to_xml_namespace() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
assert_eq!(
resolver.push(&BytesStart::from_content(
" xmlns:not_xml='http://www.w3.org/XML/1998/namespace'",
0,
)),
Err(NamespaceError::InvalidPrefixForXml(b"not_xml".to_vec())),
);
assert_eq!(&resolver.buffer[s..], b"");
}
}
mod xmlns {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn undeclared() {
let name = QName(b"xmlns:random");
let namespace = RESERVED_NAMESPACE_XMLNS.1;
let resolver = NamespaceResolver::default();
assert_eq!(
resolver.resolve(name, true),
(Bound(namespace), LocalName(b"random"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(namespace), LocalName(b"random"))
);
}
#[test]
fn rebound_to_correct_ns() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
assert_eq!(
resolver.push(&BytesStart::from_content(
" xmlns:xmlns='http://www.w3.org/2000/xmlns/'",
0,
)),
Err(NamespaceError::InvalidXmlnsPrefixBind(
b"http://www.w3.org/2000/xmlns/".to_vec()
)),
);
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn rebound_to_incorrect_ns() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
assert_eq!(
resolver.push(&BytesStart::from_content(
" xmlns:xmlns='not_correct_namespace'",
0,
)),
Err(NamespaceError::InvalidXmlnsPrefixBind(
b"not_correct_namespace".to_vec()
)),
);
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn unbound() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
assert_eq!(
resolver.push(&BytesStart::from_content(" xmlns:xmlns=''", 0)),
Err(NamespaceError::InvalidXmlnsPrefixBind(b"".to_vec())),
);
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn other_prefix_bound_to_xmlns_namespace() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
assert_eq!(
resolver.push(&BytesStart::from_content(
" xmlns:not_xmlns='http://www.w3.org/2000/xmlns/'",
0,
)),
Err(NamespaceError::InvalidPrefixForXmlns(b"not_xmlns".to_vec())),
);
assert_eq!(&resolver.buffer[s..], b"");
}
}
}
#[test]
fn undeclared_prefix() {
let name = QName(b"unknown:prefix");
let resolver = NamespaceResolver::default();
assert_eq!(
resolver.buffer,
b"xmlhttp://www.w3.org/XML/1998/namespacexmlnshttp://www.w3.org/2000/xmlns/"
);
assert_eq!(
resolver.resolve(name, true),
(Unknown(b"unknown".to_vec()), LocalName(b"prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Unknown(b"unknown".to_vec()), LocalName(b"prefix"))
);
}
#[test]
fn prefix_and_local_name() {
let name = QName(b"foo:bus");
assert_eq!(name.prefix(), Some(Prefix(b"foo")));
assert_eq!(name.local_name(), LocalName(b"bus"));
assert_eq!(name.decompose(), (LocalName(b"bus"), Some(Prefix(b"foo"))));
let name = QName(b"foo:");
assert_eq!(name.prefix(), Some(Prefix(b"foo")));
assert_eq!(name.local_name(), LocalName(b""));
assert_eq!(name.decompose(), (LocalName(b""), Some(Prefix(b"foo"))));
let name = QName(b":foo");
assert_eq!(name.prefix(), Some(Prefix(b"")));
assert_eq!(name.local_name(), LocalName(b"foo"));
assert_eq!(name.decompose(), (LocalName(b"foo"), Some(Prefix(b""))));
let name = QName(b"foo:bus:baz");
assert_eq!(name.prefix(), Some(Prefix(b"foo")));
assert_eq!(name.local_name(), LocalName(b"bus:baz"));
assert_eq!(
name.decompose(),
(LocalName(b"bus:baz"), Some(Prefix(b"foo")))
);
}
}