xee_name/
namespaces.rs

1use ahash::{HashMap, HashMapExt};
2use std::sync::LazyLock;
3
4/// The XPath FN namespace URI
5pub const FN_NAMESPACE: &str = "http://www.w3.org/2005/xpath-functions";
6/// The XML Schema XS namespace URI
7pub const XS_NAMESPACE: &str = "http://www.w3.org/2001/XMLSchema";
8const XML_NAMESPACE: &str = "http://www.w3.org/XML/1998/namespace";
9
10const STATIC_NAMESPACES: [(&str, &str); 7] = [
11    ("xs", XS_NAMESPACE),
12    ("fn", FN_NAMESPACE),
13    ("math", "http://www.w3.org/2005/xpath-functions/math"),
14    ("map", "http://www.w3.org/2005/xpath-functions/map"),
15    ("array", "http://www.w3.org/2005/xpath-functions/array"),
16    ("err", "http://www.w3.org/2005/xqt-errors"),
17    ("output", "http://www.w3.org/2010/xslt-xquery-serialization"),
18];
19
20/// Static default namespaces.
21pub static DEFAULT_NAMESPACES: LazyLock<Namespaces> = LazyLock::new(|| Default::default());
22
23/// Declared namespaces.
24#[derive(Debug, Clone)]
25pub struct Namespaces {
26    namespaces: HashMap<String, String>,
27    /// The default namespace for elements in XPath expressions.
28    pub default_element_namespace: String,
29    /// The default namespace for functions in XPath expressions.
30    pub default_function_namespace: String,
31}
32
33impl Namespaces {
34    /// The XPath FN namespace URI
35    pub const FN_NAMESPACE: &'static str = FN_NAMESPACE;
36
37    /// Create a new namespace struct.
38    pub fn new(
39        namespaces: HashMap<String, String>,
40        default_element_namespace: String,
41        default_function_namespace: String,
42    ) -> Self {
43        Self {
44            namespaces,
45            default_element_namespace,
46            default_function_namespace,
47        }
48    }
49
50    /// The default known namespaces for XPath.
51    pub fn default_namespaces() -> HashMap<String, String> {
52        let mut namespaces = HashMap::new();
53        namespaces.insert("xml".to_string(), XML_NAMESPACE.to_string());
54        for (prefix, uri) in STATIC_NAMESPACES.into_iter() {
55            namespaces.insert(prefix.to_string(), uri.to_string());
56        }
57        namespaces
58    }
59
60    /// Add a list of namespace declarations (prefix, uri) to the namespace
61    /// store.
62    pub fn add(&mut self, namespace_pairs: &[(&str, &str)]) {
63        for (prefix, namespace) in namespace_pairs {
64            if prefix.is_empty() {
65                self.default_element_namespace = namespace.to_string();
66            } else {
67                self.namespaces
68                    .insert(prefix.to_string(), namespace.to_string());
69            }
70        }
71    }
72
73    /// Get the namespace URI for a given prefix.
74    #[inline]
75    pub fn by_prefix(&self, prefix: &str) -> Option<&str> {
76        self.namespaces.get(prefix).map(String::as_str)
77    }
78
79    /// Get the default element namespace.
80    #[inline]
81    pub fn default_element_namespace(&self) -> &str {
82        self.default_element_namespace.as_str()
83    }
84}
85
86impl Default for Namespaces {
87    fn default() -> Self {
88        Self::new(
89            Self::default_namespaces(),
90            "".to_string(),
91            FN_NAMESPACE.to_string(),
92        )
93    }
94}
95
96/// A trait for looking up namespace URIs by prefix.
97pub trait NamespaceLookup {
98    /// Get the namespace URI for a given prefix.
99    fn by_prefix(&self, prefix: &str) -> Option<&str>;
100}
101
102impl NamespaceLookup for Namespaces {
103    fn by_prefix(&self, prefix: &str) -> Option<&str> {
104        self.namespaces.get(prefix).map(String::as_str)
105    }
106}
107
108impl<T: NamespaceLookup> NamespaceLookup for &T {
109    fn by_prefix(&self, prefix: &str) -> Option<&str> {
110        (**self).by_prefix(prefix)
111    }
112}