xml_3dm/node/
namespace.rs1use std::collections::HashMap;
4use std::rc::Rc;
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8pub struct ExpandedName {
9 pub namespace_uri: Rc<str>,
11 pub local_name: String,
13}
14
15impl ExpandedName {
16 pub fn new(uri: impl Into<Rc<str>>, local: impl Into<String>) -> Self {
18 Self {
19 namespace_uri: uri.into(),
20 local_name: local.into(),
21 }
22 }
23
24 pub fn no_namespace(local: impl Into<String>) -> Self {
26 Self {
27 namespace_uri: "".into(),
28 local_name: local.into(),
29 }
30 }
31}
32
33pub struct NamespaceContext {
35 uri_cache: HashMap<String, Rc<str>>,
37 scopes: Vec<HashMap<String, Rc<str>>>,
39}
40
41impl Default for NamespaceContext {
42 fn default() -> Self {
43 Self::new()
44 }
45}
46
47impl NamespaceContext {
48 pub fn new() -> Self {
50 let mut ctx = NamespaceContext {
51 uri_cache: HashMap::new(),
52 scopes: vec![HashMap::new()],
53 };
54 ctx.bind("xml", "http://www.w3.org/XML/1998/namespace");
56 ctx
57 }
58
59 pub fn push_scope(&mut self) {
61 self.scopes.push(HashMap::new());
62 }
63
64 pub fn pop_scope(&mut self) {
66 if self.scopes.len() > 1 {
67 self.scopes.pop();
68 }
69 }
70
71 pub fn bind(&mut self, prefix: &str, uri: &str) {
73 let uri_rc = self.intern_uri(uri);
74 if let Some(scope) = self.scopes.last_mut() {
75 scope.insert(prefix.to_string(), uri_rc);
76 }
77 }
78
79 pub fn resolve(&self, prefix: &str) -> Option<Rc<str>> {
81 for scope in self.scopes.iter().rev() {
82 if let Some(uri) = scope.get(prefix) {
83 return Some(uri.clone());
84 }
85 }
86 None
87 }
88
89 pub fn default_namespace(&self) -> Option<Rc<str>> {
91 self.resolve("")
92 }
93
94 pub fn intern_uri(&mut self, uri: &str) -> Rc<str> {
96 if let Some(cached) = self.uri_cache.get(uri) {
97 cached.clone()
98 } else {
99 let rc: Rc<str> = uri.into();
100 self.uri_cache.insert(uri.to_string(), rc.clone());
101 rc
102 }
103 }
104}
105
106pub fn split_qname(qname: &str) -> (Option<&str>, &str) {
111 if let Some(pos) = qname.find(':') {
112 (Some(&qname[..pos]), &qname[pos + 1..])
113 } else {
114 (None, qname)
115 }
116}
117
118pub fn is_xmlns_attr(name: &str) -> bool {
120 name == "xmlns" || name.starts_with("xmlns:")
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn test_split_qname() {
129 assert_eq!(split_qname("svg:rect"), (Some("svg"), "rect"));
130 assert_eq!(split_qname("rect"), (None, "rect"));
131 assert_eq!(split_qname("ns:foo:bar"), (Some("ns"), "foo:bar"));
132 }
133
134 #[test]
135 fn test_namespace_context() {
136 let mut ctx = NamespaceContext::new();
137 ctx.push_scope();
138 ctx.bind("svg", "http://www.w3.org/2000/svg");
139
140 assert!(ctx.resolve("svg").is_some());
141 assert_eq!(
142 ctx.resolve("svg").unwrap().as_ref(),
143 "http://www.w3.org/2000/svg"
144 );
145
146 ctx.pop_scope();
147 assert!(ctx.resolve("svg").is_none());
148 }
149
150 #[test]
151 fn test_is_xmlns() {
152 assert!(is_xmlns_attr("xmlns"));
153 assert!(is_xmlns_attr("xmlns:svg"));
154 assert!(!is_xmlns_attr("xml:space"));
155 assert!(!is_xmlns_attr("href"));
156 }
157
158 #[test]
159 fn test_default_namespace() {
160 let mut ctx = NamespaceContext::new();
161 assert!(ctx.default_namespace().is_none());
162
163 ctx.push_scope();
164 ctx.bind("", "http://www.w3.org/1999/xhtml");
165 assert_eq!(
166 ctx.default_namespace().unwrap().as_ref(),
167 "http://www.w3.org/1999/xhtml"
168 );
169
170 ctx.pop_scope();
171 assert!(ctx.default_namespace().is_none());
172 }
173
174 #[test]
175 fn test_xml_prefix_always_bound() {
176 let ctx = NamespaceContext::new();
177 assert_eq!(
178 ctx.resolve("xml").unwrap().as_ref(),
179 "http://www.w3.org/XML/1998/namespace"
180 );
181 }
182
183 #[test]
184 fn test_scope_inheritance() {
185 let mut ctx = NamespaceContext::new();
186 ctx.push_scope();
187 ctx.bind("a", "http://example.com/a");
188
189 ctx.push_scope();
190 ctx.bind("b", "http://example.com/b");
191
192 assert!(ctx.resolve("a").is_some());
194 assert!(ctx.resolve("b").is_some());
195
196 ctx.pop_scope();
197 assert!(ctx.resolve("a").is_some());
199 assert!(ctx.resolve("b").is_none());
200 }
201}