1use indexmap::IndexMap;
8use ddex_core::namespace::NamespaceRegistry;
9use std::collections::HashSet;
10
11pub const XML_DECLARATION: &str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
13
14pub struct NamespacePrefixLock {
16 registry: NamespaceRegistry,
18 version_locks: IndexMap<String, IndexMap<String, String>>, reserved_prefixes: HashSet<String>,
22}
23
24impl NamespacePrefixLock {
25 pub fn new() -> Self {
27 let mut lock = Self {
28 registry: NamespaceRegistry::new(),
29 version_locks: IndexMap::new(),
30 reserved_prefixes: HashSet::new(),
31 };
32
33 lock.initialize_version_locks();
34 lock
35 }
36
37 fn initialize_version_locks(&mut self) {
39 let mut ern_382_prefixes = IndexMap::new();
41 ern_382_prefixes.insert("http://ddex.net/xml/ern/382".to_string(), "ern".to_string());
42 ern_382_prefixes.insert("http://ddex.net/xml/avs".to_string(), "avs".to_string());
43 ern_382_prefixes.insert("http://ddex.net/xml/avs/avs".to_string(), "avs".to_string());
44 ern_382_prefixes.insert("http://www.w3.org/2001/XMLSchema-instance".to_string(), "xsi".to_string());
45 ern_382_prefixes.insert("http://www.w3.org/2001/XMLSchema".to_string(), "xs".to_string());
46 ern_382_prefixes.insert("http://ddex.net/xml/gc".to_string(), "gc".to_string());
47 self.version_locks.insert("3.8.2".to_string(), ern_382_prefixes.clone());
48 self.version_locks.insert("382".to_string(), ern_382_prefixes);
49
50 let mut ern_42_prefixes = IndexMap::new();
52 ern_42_prefixes.insert("http://ddex.net/xml/ern/42".to_string(), "ern".to_string());
53 ern_42_prefixes.insert("http://ddex.net/xml/avs".to_string(), "avs".to_string());
54 ern_42_prefixes.insert("http://ddex.net/xml/avs/avs".to_string(), "avs".to_string());
55 ern_42_prefixes.insert("http://www.w3.org/2001/XMLSchema-instance".to_string(), "xsi".to_string());
56 ern_42_prefixes.insert("http://www.w3.org/2001/XMLSchema".to_string(), "xs".to_string());
57 ern_42_prefixes.insert("http://ddex.net/xml/gc".to_string(), "gc".to_string());
58 ern_42_prefixes.insert("http://ddex.net/xml/mead/mead".to_string(), "mead".to_string());
60 ern_42_prefixes.insert("http://ddex.net/xml/pie/pie".to_string(), "pie".to_string());
61 self.version_locks.insert("4.2".to_string(), ern_42_prefixes.clone());
62 self.version_locks.insert("42".to_string(), ern_42_prefixes);
63
64 let mut ern_43_prefixes = IndexMap::new();
66 ern_43_prefixes.insert("http://ddex.net/xml/ern/43".to_string(), "ern".to_string());
67 ern_43_prefixes.insert("http://ddex.net/xml/avs".to_string(), "avs".to_string());
68 ern_43_prefixes.insert("http://ddex.net/xml/avs/avs".to_string(), "avs".to_string());
69 ern_43_prefixes.insert("http://www.w3.org/2001/XMLSchema-instance".to_string(), "xsi".to_string());
70 ern_43_prefixes.insert("http://www.w3.org/2001/XMLSchema".to_string(), "xs".to_string());
71 ern_43_prefixes.insert("http://ddex.net/xml/gc".to_string(), "gc".to_string());
72 ern_43_prefixes.insert("http://ddex.net/xml/mead/mead".to_string(), "mead".to_string());
74 ern_43_prefixes.insert("http://ddex.net/xml/pie/pie".to_string(), "pie".to_string());
75 ern_43_prefixes.insert("http://ddex.net/xml/rin/rin".to_string(), "rin".to_string());
76 ern_43_prefixes.insert("http://ddex.net/xml/dsrf".to_string(), "dsrf".to_string());
77 self.version_locks.insert("4.3".to_string(), ern_43_prefixes.clone());
78 self.version_locks.insert("43".to_string(), ern_43_prefixes);
79
80 for prefixes in self.version_locks.values() {
82 for prefix in prefixes.values() {
83 self.reserved_prefixes.insert(prefix.clone());
84 }
85 }
86 }
87
88 pub fn get_locked_prefix(&self, uri: &str, version: &str) -> Option<&str> {
90 self.version_locks
91 .get(version)
92 .and_then(|prefixes| prefixes.get(uri))
93 .map(|prefix| prefix.as_str())
94 }
95
96 pub fn get_version_prefixes(&self, version: &str) -> Option<&IndexMap<String, String>> {
98 self.version_locks.get(version)
99 }
100
101 pub fn deduplicate_prefixes(&self, declarations: &IndexMap<String, String>, version: &str) -> IndexMap<String, String> {
103 let mut deduplicated = IndexMap::new();
104 let locked_prefixes = self.get_version_prefixes(version).cloned().unwrap_or_default();
105
106 for (original_prefix, uri) in declarations {
108 if let Some(locked_prefix) = locked_prefixes.get(uri) {
109 deduplicated.insert(locked_prefix.clone(), uri.clone());
110 } else {
111 deduplicated.insert(original_prefix.clone(), uri.clone());
113 }
114 }
115
116 let mut final_declarations = IndexMap::new();
118 let mut used_prefixes = HashSet::new();
119
120 for (prefix, uri) in deduplicated {
121 if used_prefixes.contains(&prefix) {
122 let unique_prefix = self.generate_unique_prefix(&prefix, &used_prefixes);
124 used_prefixes.insert(unique_prefix.clone());
125 final_declarations.insert(unique_prefix, uri);
126 } else {
127 used_prefixes.insert(prefix.clone());
128 final_declarations.insert(prefix, uri);
129 }
130 }
131
132 final_declarations
133 }
134
135 fn generate_unique_prefix(&self, base_prefix: &str, used_prefixes: &HashSet<String>) -> String {
137 let mut counter = 1;
138 loop {
139 let candidate = format!("{}{}", base_prefix, counter);
140 if !used_prefixes.contains(&candidate) && !self.reserved_prefixes.contains(&candidate) {
141 return candidate;
142 }
143 counter += 1;
144 }
145 }
146}
147
148pub struct ElementOrder {
150 version_orders: IndexMap<String, IndexMap<String, Vec<String>>>, }
153
154impl ElementOrder {
155 pub fn new() -> Self {
157 let mut order = Self {
158 version_orders: IndexMap::new(),
159 };
160
161 order.initialize_element_orders();
162 order
163 }
164
165 fn initialize_element_orders(&mut self) {
167 let mut ern_382_order = IndexMap::new();
169 self.add_common_orders(&mut ern_382_order);
170 self.add_ern_382_specific_orders(&mut ern_382_order);
171 self.version_orders.insert("3.8.2".to_string(), ern_382_order.clone());
172 self.version_orders.insert("382".to_string(), ern_382_order);
173
174 let mut ern_42_order = IndexMap::new();
176 self.add_common_orders(&mut ern_42_order);
177 self.add_ern_42_specific_orders(&mut ern_42_order);
178 self.version_orders.insert("4.2".to_string(), ern_42_order.clone());
179 self.version_orders.insert("42".to_string(), ern_42_order);
180
181 let mut ern_43_order = IndexMap::new();
183 self.add_common_orders(&mut ern_43_order);
184 self.add_ern_43_specific_orders(&mut ern_43_order);
185 self.version_orders.insert("4.3".to_string(), ern_43_order.clone());
186 self.version_orders.insert("43".to_string(), ern_43_order);
187 }
188
189 fn add_common_orders(&self, order: &mut IndexMap<String, Vec<String>>) {
191 order.insert("MessageHeader".to_string(), vec![
193 "MessageId".to_string(),
194 "MessageType".to_string(),
195 "MessageCreatedDateTime".to_string(),
196 "MessageSender".to_string(),
197 "MessageRecipient".to_string(),
198 "MessageControlType".to_string(),
199 ]);
200
201 order.insert("Party".to_string(), vec![
203 "PartyReference".to_string(),
204 "PartyId".to_string(),
205 "PartyName".to_string(),
206 "PartyType".to_string(),
207 ]);
208
209 order.insert("Release".to_string(), vec![
211 "ReleaseReference".to_string(),
212 "ReleaseId".to_string(),
213 "ReferenceTitle".to_string(),
214 "ReleaseType".to_string(),
215 "ReleaseResourceReferenceList".to_string(),
216 "ReleaseDetailsByTerritory".to_string(),
217 ]);
218
219 order.insert("Deal".to_string(), vec![
221 "DealReference".to_string(),
222 "DealTerms".to_string(),
223 "DealReleaseReference".to_string(),
224 ]);
225 }
226
227 fn add_ern_382_specific_orders(&self, order: &mut IndexMap<String, Vec<String>>) {
229 order.insert("SoundRecording".to_string(), vec![
231 "SoundRecordingType".to_string(),
232 "SoundRecordingId".to_string(),
233 "ReferenceTitle".to_string(),
234 "Duration".to_string(),
235 "CreationDate".to_string(),
236 "SoundRecordingDetailsByTerritory".to_string(),
237 ]);
238 }
239
240 fn add_ern_42_specific_orders(&self, order: &mut IndexMap<String, Vec<String>>) {
242 order.insert("MessageHeader".to_string(), vec![
244 "MessageId".to_string(),
245 "MessageType".to_string(),
246 "MessageCreatedDateTime".to_string(),
247 "MessageSender".to_string(),
248 "MessageRecipient".to_string(),
249 "MessageControlType".to_string(),
250 "MessageAuditTrail".to_string(),
251 ]);
252
253 order.insert("SoundRecording".to_string(), vec![
255 "SoundRecordingType".to_string(),
256 "SoundRecordingId".to_string(),
257 "ReferenceTitle".to_string(),
258 "DisplayTitle".to_string(),
259 "Duration".to_string(),
260 "CreationDate".to_string(),
261 "MasteredDate".to_string(),
262 "SoundRecordingDetailsByTerritory".to_string(),
263 ]);
264 }
265
266 fn add_ern_43_specific_orders(&self, order: &mut IndexMap<String, Vec<String>>) {
268 order.insert("MessageHeader".to_string(), vec![
270 "MessageId".to_string(),
271 "MessageType".to_string(),
272 "MessageCreatedDateTime".to_string(),
273 "MessageSender".to_string(),
274 "MessageRecipient".to_string(),
275 "MessageControlType".to_string(),
276 "MessageAuditTrail".to_string(),
277 ]);
278
279 order.insert("SoundRecording".to_string(), vec![
281 "SoundRecordingType".to_string(),
282 "SoundRecordingId".to_string(),
283 "ReferenceTitle".to_string(),
284 "DisplayTitle".to_string(),
285 "DisplayTitleText".to_string(),
286 "Duration".to_string(),
287 "CreationDate".to_string(),
288 "MasteredDate".to_string(),
289 "OriginalResourceReleaseDate".to_string(),
290 "SoundRecordingDetailsByTerritory".to_string(),
291 ]);
292
293 order.insert("Video".to_string(), vec![
295 "VideoType".to_string(),
296 "VideoId".to_string(),
297 "ReferenceTitle".to_string(),
298 "DisplayTitle".to_string(),
299 "Duration".to_string(),
300 "CreationDate".to_string(),
301 "VideoDetailsByTerritory".to_string(),
302 ]);
303
304 order.insert("Image".to_string(), vec![
306 "ImageType".to_string(),
307 "ImageId".to_string(),
308 "ReferenceTitle".to_string(),
309 "DisplayTitle".to_string(),
310 "CreationDate".to_string(),
311 "ImageDetailsByTerritory".to_string(),
312 ]);
313 }
314
315 pub fn get_element_order(&self, parent_element: &str, version: &str) -> Option<&Vec<String>> {
317 self.version_orders
318 .get(version)
319 .and_then(|orders| orders.get(parent_element))
320 }
321
322 pub fn get_version_orders(&self, version: &str) -> Option<&IndexMap<String, Vec<String>>> {
324 self.version_orders.get(version)
325 }
326}
327
328pub struct AVSNamespaceHandler {
330 avs_namespaces: IndexMap<String, String>,
332}
333
334impl AVSNamespaceHandler {
335 pub fn new() -> Self {
337 let mut handler = Self {
338 avs_namespaces: IndexMap::new(),
339 };
340
341 handler.avs_namespaces.insert("http://ddex.net/xml/avs".to_string(), "avs".to_string());
343 handler.avs_namespaces.insert("http://ddex.net/xml/avs/avs".to_string(), "avs".to_string());
344
345 handler
346 }
347
348 pub fn is_avs_namespace(&self, uri: &str) -> bool {
350 self.avs_namespaces.contains_key(uri)
351 }
352
353 pub fn get_avs_prefix(&self, uri: &str) -> Option<&str> {
355 self.avs_namespaces.get(uri).map(|prefix| prefix.as_str())
356 }
357}
358
359pub struct CanonicalNamespaceManager {
361 prefix_lock: NamespacePrefixLock,
363 element_order: ElementOrder,
365 avs_handler: AVSNamespaceHandler,
367}
368
369impl CanonicalNamespaceManager {
370 pub fn new() -> Self {
372 Self {
373 prefix_lock: NamespacePrefixLock::new(),
374 element_order: ElementOrder::new(),
375 avs_handler: AVSNamespaceHandler::new(),
376 }
377 }
378
379 pub fn canonicalize_namespaces(
381 &self,
382 declarations: &IndexMap<String, String>,
383 version: &str
384 ) -> IndexMap<String, String> {
385 let locked_declarations = self.prefix_lock.deduplicate_prefixes(declarations, version);
387
388 let mut sorted_declarations: Vec<_> = locked_declarations.into_iter().collect();
390 sorted_declarations.sort_by(|a, b| a.0.cmp(&b.0));
391
392 sorted_declarations.into_iter().collect()
393 }
394
395 pub fn get_canonical_element_order(&self, parent: &str, version: &str) -> Option<&Vec<String>> {
397 self.element_order.get_element_order(parent, version)
398 }
399
400 pub fn requires_avs_handling(&self, uri: &str) -> bool {
402 self.avs_handler.is_avs_namespace(uri)
403 }
404}
405
406impl Default for NamespacePrefixLock {
407 fn default() -> Self {
408 Self::new()
409 }
410}
411
412impl Default for ElementOrder {
413 fn default() -> Self {
414 Self::new()
415 }
416}
417
418impl Default for AVSNamespaceHandler {
419 fn default() -> Self {
420 Self::new()
421 }
422}
423
424impl Default for CanonicalNamespaceManager {
425 fn default() -> Self {
426 Self::new()
427 }
428}
429
430pub fn get_namespace_prefixes(version: &str) -> IndexMap<String, String> {
434 let lock = NamespacePrefixLock::new();
435 lock.get_version_prefixes(version).cloned().unwrap_or_default()
436}
437
438pub fn get_element_order(version: &str) -> IndexMap<String, Vec<String>> {
440 let order = ElementOrder::new();
441 order.get_version_orders(version).cloned().unwrap_or_default()
442}
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447
448 #[test]
449 fn test_namespace_prefix_lock() {
450 let lock = NamespacePrefixLock::new();
451
452 assert_eq!(
453 lock.get_locked_prefix("http://ddex.net/xml/ern/43", "4.3"),
454 Some("ern")
455 );
456 assert_eq!(
457 lock.get_locked_prefix("http://ddex.net/xml/avs", "4.3"),
458 Some("avs")
459 );
460 }
461
462 #[test]
463 fn test_prefix_deduplication() {
464 let lock = NamespacePrefixLock::new();
465
466 let mut declarations = IndexMap::new();
467 declarations.insert("custom_ern".to_string(), "http://ddex.net/xml/ern/43".to_string());
468 declarations.insert("avs".to_string(), "http://ddex.net/xml/avs".to_string());
469
470 let deduplicated = lock.deduplicate_prefixes(&declarations, "4.3");
471
472 assert_eq!(deduplicated.get("ern"), Some(&"http://ddex.net/xml/ern/43".to_string()));
474 assert_eq!(deduplicated.get("avs"), Some(&"http://ddex.net/xml/avs".to_string()));
475 }
476
477 #[test]
478 fn test_element_order() {
479 let order = ElementOrder::new();
480
481 let message_order = order.get_element_order("MessageHeader", "4.3");
482 assert!(message_order.is_some());
483
484 let order_vec = message_order.unwrap();
485 assert_eq!(order_vec[0], "MessageId");
486 assert_eq!(order_vec[1], "MessageType");
487 }
488
489 #[test]
490 fn test_avs_namespace_handler() {
491 let handler = AVSNamespaceHandler::new();
492
493 assert!(handler.is_avs_namespace("http://ddex.net/xml/avs"));
494 assert_eq!(handler.get_avs_prefix("http://ddex.net/xml/avs"), Some("avs"));
495 assert!(!handler.is_avs_namespace("http://ddex.net/xml/ern/43"));
496 }
497
498 #[test]
499 fn test_canonical_namespace_manager() {
500 let manager = CanonicalNamespaceManager::new();
501
502 let mut declarations = IndexMap::new();
503 declarations.insert("z_ern".to_string(), "http://ddex.net/xml/ern/43".to_string());
504 declarations.insert("a_avs".to_string(), "http://ddex.net/xml/avs".to_string());
505
506 let canonical = manager.canonicalize_namespaces(&declarations, "4.3");
507
508 let keys: Vec<_> = canonical.keys().collect();
510 assert!(keys.len() >= 2);
511 assert!(canonical.contains_key("ern"));
513 assert!(canonical.contains_key("avs"));
514 }
515}