1use std::collections::BTreeMap;
2
3use super::{validate_namespace_binding, NamespacePrefix, NamespaceUri, XmlResult};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct NamespaceDeclaration {
8 prefix: Option<NamespacePrefix>,
9 uri: NamespaceUri,
10}
11
12impl NamespaceDeclaration {
13 pub fn default(uri: impl Into<String>) -> XmlResult<Self> {
14 let uri = uri.into();
15 validate_namespace_binding(None, &uri)?;
16 Ok(Self {
17 prefix: None,
18 uri: NamespaceUri::new(uri)?,
19 })
20 }
21
22 pub fn prefixed(prefix: impl Into<String>, uri: impl Into<String>) -> XmlResult<Self> {
23 let prefix = prefix.into();
24 let uri = uri.into();
25 validate_namespace_binding(Some(&prefix), &uri)?;
26 Ok(Self {
27 prefix: Some(NamespacePrefix::new(prefix)?),
28 uri: NamespaceUri::new(uri)?,
29 })
30 }
31
32 pub fn prefix(&self) -> Option<&NamespacePrefix> {
33 self.prefix.as_ref()
34 }
35
36 pub fn uri(&self) -> &NamespaceUri {
37 &self.uri
38 }
39}
40
41#[derive(Debug, Clone, Default, PartialEq, Eq)]
43pub struct NamespaceTable {
44 default_namespace: Option<NamespaceUri>,
45 prefixed: BTreeMap<NamespacePrefix, NamespaceUri>,
46}
47
48impl NamespaceTable {
49 pub fn new() -> Self {
50 Self::default()
51 }
52
53 pub fn declare(&mut self, declaration: NamespaceDeclaration) {
54 match declaration.prefix {
55 Some(prefix) => {
56 self.prefixed.insert(prefix, declaration.uri);
57 }
58 None => {
59 self.default_namespace = Some(declaration.uri);
60 }
61 }
62 }
63
64 pub fn declare_default(&mut self, uri: impl Into<String>) -> XmlResult<()> {
65 self.declare(NamespaceDeclaration::default(uri)?);
66 Ok(())
67 }
68
69 pub fn declare_prefix(
70 &mut self,
71 prefix: impl Into<String>,
72 uri: impl Into<String>,
73 ) -> XmlResult<()> {
74 self.declare(NamespaceDeclaration::prefixed(prefix, uri)?);
75 Ok(())
76 }
77
78 pub fn default_namespace(&self) -> Option<&NamespaceUri> {
79 self.default_namespace.as_ref()
80 }
81
82 pub fn resolve_prefix(&self, prefix: &NamespacePrefix) -> Option<&NamespaceUri> {
83 self.prefixed.get(prefix)
84 }
85
86 pub fn iter_prefixed(&self) -> impl Iterator<Item = (&NamespacePrefix, &NamespaceUri)> {
87 self.prefixed.iter()
88 }
89
90 pub fn len(&self) -> usize {
91 self.prefixed.len() + usize::from(self.default_namespace.is_some())
92 }
93
94 pub fn is_empty(&self) -> bool {
95 self.default_namespace.is_none() && self.prefixed.is_empty()
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn namespace_table_registers_and_resolves_prefixes() {
105 let mut table = NamespaceTable::new();
106 table
107 .declare_prefix("cbc", "urn:example:cbc")
108 .expect("valid namespace");
109
110 let prefix = NamespacePrefix::new("cbc").expect("valid prefix");
111 assert_eq!(
112 table.resolve_prefix(&prefix).map(NamespaceUri::as_str),
113 Some("urn:example:cbc")
114 );
115 }
116
117 #[test]
118 fn namespace_table_resolves_default_namespace() {
119 let mut table = NamespaceTable::new();
120 table
121 .declare_default("urn:example:document")
122 .expect("valid namespace");
123
124 assert_eq!(
125 table.default_namespace().map(NamespaceUri::as_str),
126 Some("urn:example:document")
127 );
128 }
129
130 #[test]
131 fn namespace_declaration_rejects_invalid_prefix() {
132 let error = NamespaceDeclaration::prefixed("", "urn:example")
133 .expect_err("empty namespace prefix must fail");
134
135 assert_eq!(error.kind(), &super::super::ErrorKind::InvalidName);
136 }
137
138 #[test]
139 fn namespace_declaration_respects_reserved_xml_bindings() {
140 NamespaceDeclaration::prefixed("xml", super::super::XML_NAMESPACE_URI)
141 .expect("xml prefix binding");
142
143 assert_eq!(
144 NamespaceDeclaration::prefixed("xml", "urn:wrong")
145 .expect_err("xml prefix must use XML namespace URI")
146 .kind(),
147 &super::super::ErrorKind::InvalidNamespace
148 );
149 assert_eq!(
150 NamespaceDeclaration::prefixed("doc", super::super::XML_NAMESPACE_URI)
151 .expect_err("XML namespace URI is reserved for xml prefix")
152 .kind(),
153 &super::super::ErrorKind::InvalidNamespace
154 );
155 assert_eq!(
156 NamespaceDeclaration::prefixed("xmlns", "urn:any")
157 .expect_err("xmlns prefix is reserved")
158 .kind(),
159 &super::super::ErrorKind::InvalidNamespace
160 );
161 assert_eq!(
162 NamespaceDeclaration::default(super::super::XMLNS_NAMESPACE_URI)
163 .expect_err("XMLNS namespace URI cannot be declared")
164 .kind(),
165 &super::super::ErrorKind::InvalidNamespace
166 );
167 }
168
169 #[test]
170 fn namespace_table_keeps_prefixed_bindings_deterministic() {
171 let mut table = NamespaceTable::new();
172 table.declare_prefix("z", "urn:z").expect("valid namespace");
173 table.declare_prefix("a", "urn:a").expect("valid namespace");
174
175 let prefixes = table
176 .iter_prefixed()
177 .map(|(prefix, _)| prefix.as_str())
178 .collect::<Vec<_>>();
179
180 assert_eq!(prefixes, vec!["a", "z"]);
181 }
182}