xpath/
context.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::fmt;
6
7use crate::{Dom, NamespaceResolver, Node};
8
9/// The context during evaluation of an XPath expression.
10pub(crate) struct EvaluationCtx<D: Dom> {
11    /// Where we started at.
12    pub(crate) starting_node: D::Node,
13    /// The "current" node in the evaluation.
14    pub(crate) context_node: D::Node,
15    /// Details needed for evaluating a predicate list.
16    pub(crate) predicate_ctx: Option<PredicateCtx>,
17    /// A list of known namespace prefixes.
18    pub(crate) resolver: Option<D::NamespaceResolver>,
19}
20
21#[derive(Clone, Copy, Debug)]
22pub(crate) struct PredicateCtx {
23    pub(crate) index: usize,
24    pub(crate) size: usize,
25}
26
27impl<D: Dom> EvaluationCtx<D> {
28    /// Prepares the context used while evaluating the XPath expression
29    pub(crate) fn new(context_node: D::Node, resolver: Option<D::NamespaceResolver>) -> Self {
30        EvaluationCtx {
31            starting_node: context_node.clone(),
32            context_node,
33            predicate_ctx: None,
34            resolver,
35        }
36    }
37
38    /// Creates a new context using the provided node as the context node
39    pub(crate) fn subcontext_for_node(&self, node: D::Node) -> Self {
40        EvaluationCtx {
41            starting_node: self.starting_node.clone(),
42            context_node: node,
43            predicate_ctx: self.predicate_ctx,
44            resolver: self.resolver.clone(),
45        }
46    }
47
48    /// Resolve a namespace prefix using the context node's document
49    pub(crate) fn resolve_namespace(
50        &self,
51        prefix: Option<&str>,
52    ) -> Result<Option<String>, D::JsError> {
53        // First check if the prefix is known by our resolver function
54        if let Some(resolver) = self.resolver.as_ref() {
55            if let Some(namespace_uri) = resolver.resolve_namespace_prefix(prefix)? {
56                return Ok(Some(namespace_uri));
57            }
58        }
59
60        // Then, see if it's defined on the context node
61        Ok(self.context_node.lookup_namespace_uri(prefix))
62    }
63}
64
65impl<D: Dom> fmt::Debug for EvaluationCtx<D> {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        f.debug_struct("EvaluationCtx")
68            .field("starting_node", &self.starting_node)
69            .field("context_node", &self.context_node)
70            .field("predicate_ctx", &self.predicate_ctx)
71            .field("resolver", &"<callback function>")
72            .finish()
73    }
74}