Skip to content

Commit 5ea16e1

Browse files
committed
Make NamespaceResolver public and better document it
1 parent c7e740d commit 5ea16e1

File tree

3 files changed

+138
-24
lines changed

3 files changed

+138
-24
lines changed

Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
### New Features
1818

1919
- [#893]: Implement `FusedIterator` for `NamespaceBindingsIter`.
20+
- [#893]: Make `NamespaceResolver` public.
21+
- [#893]: Add `NsReader::resolver()` for access to namespace resolver.
2022

2123
### Bug Fixes
2224

src/name.rs

Lines changed: 123 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ impl<'a> AsRef<[u8]> for Namespace<'a> {
365365

366366
////////////////////////////////////////////////////////////////////////////////////////////////////
367367

368-
/// Result of [prefix] resolution which creates by [`NsReader::resolve_attribute`],
368+
/// Result of [prefix] resolution which creates by [`NamespaceResolver::resolve`], [`NsReader::resolve_attribute`],
369369
/// [`NsReader::resolve_element`], [`NsReader::read_resolved_event`] and
370370
/// [`NsReader::read_resolved_event_into`] methods.
371371
///
@@ -478,11 +478,12 @@ impl NamespaceBinding {
478478
}
479479
}
480480

481-
/// A namespace management buffer.
481+
/// A storage for currently defined namespace bindings, which is used to resolve
482+
/// prefixes into namespaces.
482483
///
483484
/// Holds all internal logic to push/pop namespaces with their levels.
484485
#[derive(Debug, Clone)]
485-
pub(crate) struct NamespaceResolver {
486+
pub struct NamespaceResolver {
486487
/// Buffer that contains names of namespace prefixes (the part between `xmlns:`
487488
/// and an `=`) and namespace values.
488489
buffer: Vec<u8>,
@@ -510,7 +511,7 @@ const RESERVED_NAMESPACE_XML: (Prefix, Namespace) = (
510511
/// The prefix `xmlns` is used only to declare namespace bindings and is by definition bound
511512
/// to the namespace name `http://www.w3.org/2000/xmlns/`. It must not be declared or
512513
/// undeclared. Other prefixes must not be bound to this namespace name, and it must not be
513-
/// declared as the default namespace. Element names must not have the prefix `xmlns`.
514+
/// declared as the default namespace. Element names must not have the prefix `xmlns`.
514515
///
515516
/// [reserved namespaces]: https://www.w3.org/TR/xml-names11/#xmlReserved
516517
const RESERVED_NAMESPACE_XMLNS: (Prefix, Namespace) = (
@@ -547,7 +548,7 @@ impl NamespaceResolver {
547548
/// Begins a new scope and add to it all [namespace bindings] that found in
548549
/// the specified start element.
549550
///
550-
/// [namespace binding]: https://www.w3.org/TR/xml-names11/#dt-NSDecl
551+
/// [namespace bindings]: https://www.w3.org/TR/xml-names11/#dt-NSDecl
551552
pub fn push(&mut self, start: &BytesStart) -> Result<(), NamespaceError> {
552553
self.nesting_level += 1;
553554
let level = self.nesting_level;
@@ -607,10 +608,10 @@ impl NamespaceResolver {
607608
Ok(())
608609
}
609610

610-
/// Ends a top-most scope by popping all [namespace binding], that was added by
611+
/// Ends a top-most scope by popping all [namespace bindings], that was added by
611612
/// last call to [`Self::push()`].
612613
///
613-
/// [namespace binding]: https://www.w3.org/TR/xml-names11/#dt-NSDecl
614+
/// [namespace bindings]: https://www.w3.org/TR/xml-names11/#dt-NSDecl
614615
pub fn pop(&mut self) {
615616
self.nesting_level -= 1;
616617
let current_level = self.nesting_level;
@@ -632,18 +633,38 @@ impl NamespaceResolver {
632633
}
633634

634635
/// Resolves a potentially qualified **element name** or **attribute name**
635-
/// into (namespace name, local name).
636+
/// into _(namespace name, local name)_.
636637
///
637-
/// *Qualified* names have the form `prefix:local-name` where the `prefix` is
638-
/// defined on any containing XML element via `xmlns:prefix="the:namespace:uri"`.
639-
/// The namespace prefix can be defined on the same element as the element or
640-
/// attribute in question.
638+
/// _Qualified_ names have the form `local-name` or `prefix:local-name` where the `prefix`
639+
/// is defined on any containing XML element via `xmlns:prefix="the:namespace:uri"`.
640+
/// The namespace prefix can be defined on the same element as the name in question.
641641
///
642-
/// *Unqualified* attribute names do *not* inherit the current *default namespace*.
642+
/// The method returns following results depending on the `name` shape, `attribute` flag
643+
/// and the presence of the default namespace on element or any of its parents:
644+
///
645+
/// |use_default|`xmlns="..."`|QName |ResolveResult |LocalName
646+
/// |-----------|-------------|-------------------|-----------------------|------------
647+
/// |`false` |_(any)_ |`local-name` |[`Unbound`] |`local-name`
648+
/// |`false` |_(any)_ |`prefix:local-name`|[`Bound`] / [`Unknown`]|`local-name`
649+
/// |`true` |Not defined |`local-name` |[`Unbound`] |`local-name`
650+
/// |`true` |Defined |`local-name` |[`Bound`] (to `xmlns`) |`local-name`
651+
/// |`true` |_(any)_ |`prefix:local-name`|[`Bound`] / [`Unknown`]|`local-name`
652+
///
653+
/// # Parameters
654+
/// - `name`: probably qualified name to resolve;
655+
/// - `use_default`: whether to try to translate `None` prefix to the currently default namespace
656+
/// (bound using `xmlns="default namespace"`) or return [`ResolveResult::Unbound`].
657+
/// For attribute names this should be set to `false` and for element names to `true`.
643658
///
644659
/// # Lifetimes
645660
///
646-
/// - `'n`: lifetime of an attribute or an element name
661+
/// - `'n`: lifetime of a name. Returned local name will be bound to the same
662+
/// lifetime as the name in question.
663+
/// - returned namespace name will be bound to the resolver itself
664+
///
665+
/// [`Bound`]: ResolveResult::Bound
666+
/// [`Unbound`]: ResolveResult::Unbound
667+
/// [`Unknown`]: ResolveResult::Unknown
647668
#[inline]
648669
pub fn resolve<'n>(
649670
&self,
@@ -669,7 +690,14 @@ impl NamespaceResolver {
669690
self.resolve_prefix(element_name.prefix(), true)
670691
}
671692

672-
fn resolve_prefix(&self, prefix: Option<Prefix>, use_default: bool) -> ResolveResult<'_> {
693+
/// Resolves given optional prefix (usually got from [`QName`]) into a corresponding namespace.
694+
///
695+
/// # Parameters
696+
/// - `prefix`: prefix to resolve, usually result of [`QName::prefix()`];
697+
/// - `use_default`: whether to try to translate `None` prefix to the currently default namespace
698+
/// (bound using `xmlns="default namespace"`) or return [`ResolveResult::Unbound`].
699+
/// For attribute names this should be set to `false` and for element names to `true`.
700+
pub fn resolve_prefix(&self, prefix: Option<Prefix>, use_default: bool) -> ResolveResult<'_> {
673701
// Find the last defined binding that corresponds to the given prefix
674702
let mut iter = self.bindings.iter().rev();
675703
match (prefix, use_default) {
@@ -689,6 +717,85 @@ impl NamespaceResolver {
689717
}
690718
}
691719

720+
/// Returns all the bindings currently in effect except the default `xml` and `xmlns` bindings.
721+
///
722+
/// # Examples
723+
///
724+
/// This example shows what results the returned iterator would return after
725+
/// reading each event of a simple XML.
726+
///
727+
/// ```
728+
/// # use pretty_assertions::assert_eq;
729+
/// use quick_xml::name::{Namespace, PrefixDeclaration};
730+
/// use quick_xml::NsReader;
731+
///
732+
/// let src = "<root>
733+
/// <a xmlns=\"a1\" xmlns:a=\"a2\">
734+
/// <b xmlns=\"b1\" xmlns:b=\"b2\">
735+
/// <c/>
736+
/// </b>
737+
/// <d/>
738+
/// </a>
739+
/// </root>";
740+
/// let mut reader = NsReader::from_str(src);
741+
/// reader.config_mut().trim_text(true);
742+
/// // No bindings at the beginning
743+
/// assert_eq!(reader.resolver().bindings().collect::<Vec<_>>(), vec![]);
744+
///
745+
/// reader.read_resolved_event()?; // <root>
746+
/// // No bindings declared on root
747+
/// assert_eq!(reader.resolver().bindings().collect::<Vec<_>>(), vec![]);
748+
///
749+
/// reader.read_resolved_event()?; // <a>
750+
/// // Two bindings declared on "a"
751+
/// assert_eq!(reader.resolver().bindings().collect::<Vec<_>>(), vec![
752+
/// (PrefixDeclaration::Default, Namespace(b"a1")),
753+
/// (PrefixDeclaration::Named(b"a"), Namespace(b"a2"))
754+
/// ]);
755+
///
756+
/// reader.read_resolved_event()?; // <b>
757+
/// // The default prefix got overridden and new "b" prefix
758+
/// assert_eq!(reader.resolver().bindings().collect::<Vec<_>>(), vec![
759+
/// (PrefixDeclaration::Named(b"a"), Namespace(b"a2")),
760+
/// (PrefixDeclaration::Default, Namespace(b"b1")),
761+
/// (PrefixDeclaration::Named(b"b"), Namespace(b"b2"))
762+
/// ]);
763+
///
764+
/// reader.read_resolved_event()?; // <c/>
765+
/// // Still the same
766+
/// assert_eq!(reader.resolver().bindings().collect::<Vec<_>>(), vec![
767+
/// (PrefixDeclaration::Named(b"a"), Namespace(b"a2")),
768+
/// (PrefixDeclaration::Default, Namespace(b"b1")),
769+
/// (PrefixDeclaration::Named(b"b"), Namespace(b"b2"))
770+
/// ]);
771+
///
772+
/// reader.read_resolved_event()?; // </b>
773+
/// // Still the same
774+
/// assert_eq!(reader.resolver().bindings().collect::<Vec<_>>(), vec![
775+
/// (PrefixDeclaration::Named(b"a"), Namespace(b"a2")),
776+
/// (PrefixDeclaration::Default, Namespace(b"b1")),
777+
/// (PrefixDeclaration::Named(b"b"), Namespace(b"b2"))
778+
/// ]);
779+
///
780+
/// reader.read_resolved_event()?; // <d/>
781+
/// // </b> got closed so back to the bindings declared on <a>
782+
/// assert_eq!(reader.resolver().bindings().collect::<Vec<_>>(), vec![
783+
/// (PrefixDeclaration::Default, Namespace(b"a1")),
784+
/// (PrefixDeclaration::Named(b"a"), Namespace(b"a2"))
785+
/// ]);
786+
///
787+
/// reader.read_resolved_event()?; // </a>
788+
/// // Still the same
789+
/// assert_eq!(reader.resolver().bindings().collect::<Vec<_>>(), vec![
790+
/// (PrefixDeclaration::Default, Namespace(b"a1")),
791+
/// (PrefixDeclaration::Named(b"a"), Namespace(b"a2"))
792+
/// ]);
793+
///
794+
/// reader.read_resolved_event()?; // </root>
795+
/// // <a> got closed
796+
/// assert_eq!(reader.resolver().bindings().collect::<Vec<_>>(), vec![]);
797+
/// # quick_xml::Result::Ok(())
798+
/// ```
692799
#[inline]
693800
pub const fn bindings(&self) -> NamespaceBindingsIter<'_> {
694801
NamespaceBindingsIter {
@@ -703,7 +810,7 @@ impl NamespaceResolver {
703810

704811
/// Iterator on the current declared namespace bindings. Returns pairs of the _(prefix, namespace)_.
705812
///
706-
/// See [`NsReader::prefixes`](crate::NsReader::prefixes) for documentation.
813+
/// See [`NamespaceResolver::bindings`] for documentation.
707814
#[derive(Debug, Clone)]
708815
pub struct NamespaceBindingsIter<'a> {
709816
resolver: &'a NamespaceResolver,

src/reader/ns_reader.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -214,24 +214,29 @@ impl<R> NsReader<R> {
214214
self.reader.get_mut()
215215
}
216216

217+
/// Returns a storage of namespace bindings associated with this reader.
218+
#[inline]
219+
pub const fn resolver(&self) -> &NamespaceResolver {
220+
&self.ns_resolver
221+
}
222+
217223
/// Resolves a potentially qualified **element name** or **attribute name**
218224
/// into _(namespace name, local name)_.
219225
///
220-
/// _Qualified_ names have the form `prefix:local-name` where the `prefix`
226+
/// _Qualified_ names have the form `local-name` or `prefix:local-name` where the `prefix`
221227
/// is defined on any containing XML element via `xmlns:prefix="the:namespace:uri"`.
222228
/// The namespace prefix can be defined on the same element as the name in question.
223229
///
224-
/// The method returns following results depending on the `name` shape,
225-
/// `attribute` flag and the presence of the default namespace:
230+
/// The method returns following results depending on the `name` shape, `attribute` flag
231+
/// and the presence of the default namespace on element or any of its parents:
226232
///
227233
/// |attribute|`xmlns="..."`|QName |ResolveResult |LocalName
228234
/// |---------|-------------|-------------------|-----------------------|------------
229-
/// |`true` |Not defined |`local-name` |[`Unbound`] |`local-name`
230-
/// |`true` |Defined |`local-name` |[`Unbound`] |`local-name`
231-
/// |`true` |_any_ |`prefix:local-name`|[`Bound`] / [`Unknown`]|`local-name`
235+
/// |`true` |_(any)_ |`local-name` |[`Unbound`] |`local-name`
236+
/// |`true` |_(any)_ |`prefix:local-name`|[`Bound`] / [`Unknown`]|`local-name`
232237
/// |`false` |Not defined |`local-name` |[`Unbound`] |`local-name`
233-
/// |`false` |Defined |`local-name` |[`Bound`] (default) |`local-name`
234-
/// |`false` |_any_ |`prefix:local-name`|[`Bound`] / [`Unknown`]|`local-name`
238+
/// |`false` |Defined |`local-name` |[`Bound`] (to `xmlns`) |`local-name`
239+
/// |`false` |_(any)_ |`prefix:local-name`|[`Bound`] / [`Unknown`]|`local-name`
235240
///
236241
/// If you want to clearly indicate that name that you resolve is an element
237242
/// or an attribute name, you could use [`resolve_attribute()`] or [`resolve_element()`]

0 commit comments

Comments
 (0)