1use ahash::{HashMap, HashMapExt};
2use std::sync::LazyLock;
3
4pub const FN_NAMESPACE: &str = "http://www.w3.org/2005/xpath-functions";
6pub 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
20pub static DEFAULT_NAMESPACES: LazyLock<Namespaces> = LazyLock::new(|| Default::default());
22
23#[derive(Debug, Clone)]
25pub struct Namespaces {
26 namespaces: HashMap<String, String>,
27 pub default_element_namespace: String,
29 pub default_function_namespace: String,
31}
32
33impl Namespaces {
34 pub const FN_NAMESPACE: &'static str = FN_NAMESPACE;
36
37 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 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 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 #[inline]
75 pub fn by_prefix(&self, prefix: &str) -> Option<&str> {
76 self.namespaces.get(prefix).map(String::as_str)
77 }
78
79 #[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
96pub trait NamespaceLookup {
98 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}