Skip to content

Commit 54fc5b3

Browse files
committed
Extract NamespaceResolver::add from NamespaceResolver::push
1 parent 58bb2b6 commit 54fc5b3

File tree

1 file changed

+109
-44
lines changed

1 file changed

+109
-44
lines changed

src/name.rs

Lines changed: 109 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -545,60 +545,125 @@ impl Default for NamespaceResolver {
545545
}
546546

547547
impl NamespaceResolver {
548+
/// Adds new binding of prefix to namespace, returns the result of operation.
549+
///
550+
/// Binding will be added on current nesting level and will be removed, when
551+
/// level will be [popped out].
552+
///
553+
/// The operation may fail if you try to (re-)declare reserved prefixes `xml` and `xmlns`.
554+
///
555+
/// Note, that method does not check if namespace was already added on that level.
556+
/// Use `resolver.bindings_of(resolver.level()).any()` if you want to check that.
557+
/// New definition will be added and replace the old.
558+
///
559+
/// Implementation detail: memory occupied by old binding of that level still will be used.
560+
///
561+
/// ```
562+
/// # use pretty_assertions::assert_eq;
563+
/// # use quick_xml::name::{Namespace, NamespaceResolver, PrefixDeclaration, QName, ResolveResult};
564+
/// #
565+
/// let mut resolver = NamespaceResolver::default();
566+
/// // names without prefix are unbound by default
567+
/// assert_eq!(
568+
/// resolver.resolve_element(QName(b"name")).0,
569+
/// ResolveResult::Unbound,
570+
/// );
571+
/// // names with undeclared prefix are unknown
572+
/// assert_eq!(
573+
/// resolver.resolve_element(QName(b"ns:name")).0,
574+
/// ResolveResult::Unknown(b"ns".to_vec()),
575+
/// );
576+
///
577+
/// resolver.add(PrefixDeclaration::Default, Namespace(b"example.com"));
578+
/// resolver.add(PrefixDeclaration::Named(b"ns"), Namespace(b"my:namespace"));
579+
///
580+
/// assert_eq!(
581+
/// resolver.resolve_element(QName(b"name")).0,
582+
/// ResolveResult::Bound(Namespace(b"example.com")),
583+
/// );
584+
/// assert_eq!(
585+
/// resolver.resolve_element(QName(b"ns:name")).0,
586+
/// ResolveResult::Bound(Namespace(b"my:namespace")),
587+
/// );
588+
///
589+
/// // adding empty namespace clears the binding
590+
/// resolver.add(PrefixDeclaration::Default, Namespace(b""));
591+
/// resolver.add(PrefixDeclaration::Named(b"ns"), Namespace(b""));
592+
///
593+
/// assert_eq!(
594+
/// resolver.resolve_element(QName(b"name")).0,
595+
/// ResolveResult::Unbound,
596+
/// );
597+
/// assert_eq!(
598+
/// resolver.resolve_element(QName(b"ns:name")).0,
599+
/// ResolveResult::Unknown(b"ns".to_vec()),
600+
/// );
601+
/// ```
602+
/// [popped out]: Self::pop
603+
pub fn add(
604+
&mut self,
605+
prefix: PrefixDeclaration,
606+
namespace: Namespace,
607+
) -> Result<(), NamespaceError> {
608+
let level = self.nesting_level;
609+
match prefix {
610+
PrefixDeclaration::Default => {
611+
let start = self.buffer.len();
612+
self.buffer.extend_from_slice(&namespace.0);
613+
self.bindings.push(NamespaceBinding {
614+
start,
615+
prefix_len: 0,
616+
value_len: namespace.0.len(),
617+
level,
618+
});
619+
}
620+
PrefixDeclaration::Named(b"xml") => {
621+
if namespace != RESERVED_NAMESPACE_XML.1 {
622+
// error, `xml` prefix explicitly set to different value
623+
return Err(NamespaceError::InvalidXmlPrefixBind(namespace.0.to_vec()));
624+
}
625+
// don't add another NamespaceEntry for the `xml` namespace prefix
626+
}
627+
PrefixDeclaration::Named(b"xmlns") => {
628+
// error, `xmlns` prefix explicitly set
629+
return Err(NamespaceError::InvalidXmlnsPrefixBind(namespace.0.to_vec()));
630+
}
631+
PrefixDeclaration::Named(prefix) => {
632+
// error, non-`xml` prefix set to xml uri
633+
if namespace == RESERVED_NAMESPACE_XML.1 {
634+
return Err(NamespaceError::InvalidPrefixForXml(prefix.to_vec()));
635+
} else
636+
// error, non-`xmlns` prefix set to xmlns uri
637+
if namespace == RESERVED_NAMESPACE_XMLNS.1 {
638+
return Err(NamespaceError::InvalidPrefixForXmlns(prefix.to_vec()));
639+
}
640+
641+
let start = self.buffer.len();
642+
self.buffer.extend_from_slice(prefix);
643+
self.buffer.extend_from_slice(&namespace.0);
644+
self.bindings.push(NamespaceBinding {
645+
start,
646+
prefix_len: prefix.len(),
647+
value_len: namespace.0.len(),
648+
level,
649+
});
650+
}
651+
}
652+
Ok(())
653+
}
654+
548655
/// Begins a new scope and add to it all [namespace bindings] that found in
549656
/// the specified start element.
550657
///
551658
/// [namespace bindings]: https://www.w3.org/TR/xml-names11/#dt-NSDecl
552659
pub fn push(&mut self, start: &BytesStart) -> Result<(), NamespaceError> {
553660
self.nesting_level += 1;
554-
let level = self.nesting_level;
555661
// adds new namespaces for attributes starting with 'xmlns:' and for the 'xmlns'
556662
// (default namespace) attribute.
557663
for a in start.attributes().with_checks(false) {
558664
if let Ok(Attribute { key: k, value: v }) = a {
559665
match k.as_namespace_binding() {
560-
Some(PrefixDeclaration::Default) => {
561-
let start = self.buffer.len();
562-
self.buffer.extend_from_slice(&v);
563-
self.bindings.push(NamespaceBinding {
564-
start,
565-
prefix_len: 0,
566-
value_len: v.len(),
567-
level,
568-
});
569-
}
570-
Some(PrefixDeclaration::Named(b"xml")) => {
571-
if Namespace(&v) != RESERVED_NAMESPACE_XML.1 {
572-
// error, `xml` prefix explicitly set to different value
573-
return Err(NamespaceError::InvalidXmlPrefixBind(v.to_vec()));
574-
}
575-
// don't add another NamespaceEntry for the `xml` namespace prefix
576-
}
577-
Some(PrefixDeclaration::Named(b"xmlns")) => {
578-
// error, `xmlns` prefix explicitly set
579-
return Err(NamespaceError::InvalidXmlnsPrefixBind(v.to_vec()));
580-
}
581-
Some(PrefixDeclaration::Named(prefix)) => {
582-
let ns = Namespace(&v);
583-
584-
if ns == RESERVED_NAMESPACE_XML.1 {
585-
// error, non-`xml` prefix set to xml uri
586-
return Err(NamespaceError::InvalidPrefixForXml(prefix.to_vec()));
587-
} else if ns == RESERVED_NAMESPACE_XMLNS.1 {
588-
// error, non-`xmlns` prefix set to xmlns uri
589-
return Err(NamespaceError::InvalidPrefixForXmlns(prefix.to_vec()));
590-
}
591-
592-
let start = self.buffer.len();
593-
self.buffer.extend_from_slice(prefix);
594-
self.buffer.extend_from_slice(&v);
595-
self.bindings.push(NamespaceBinding {
596-
start,
597-
prefix_len: prefix.len(),
598-
value_len: v.len(),
599-
level,
600-
});
601-
}
666+
Some(prefix) => self.add(prefix, Namespace(&v))?,
602667
None => {}
603668
}
604669
} else {
@@ -609,7 +674,7 @@ impl NamespaceResolver {
609674
}
610675

611676
/// Ends a top-most scope by popping all [namespace bindings], that was added by
612-
/// last call to [`Self::push()`].
677+
/// last call to [`Self::push()`] and [`Self::add()`].
613678
///
614679
/// [namespace bindings]: https://www.w3.org/TR/xml-names11/#dt-NSDecl
615680
pub fn pop(&mut self) {

0 commit comments

Comments
 (0)