1use ddex_core::namespace::NamespaceRegistry;
8use indexmap::IndexMap;
9use std::collections::HashSet;
10
11pub const XML_DECLARATION: &str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
13
14pub struct NamespacePrefixLock {
16 #[allow(dead_code)]
18 registry: NamespaceRegistry,
19 version_locks: IndexMap<String, IndexMap<String, String>>, reserved_prefixes: HashSet<String>,
23}
24
25impl NamespacePrefixLock {
26 pub fn new() -> Self {
28 let mut lock = Self {
29 registry: NamespaceRegistry::new(),
30 version_locks: IndexMap::new(),
31 reserved_prefixes: HashSet::new(),
32 };
33
34 lock.initialize_version_locks();
35 lock
36 }
37
38 fn initialize_version_locks(&mut self) {
40 let mut ern_382_prefixes = IndexMap::new();
42 ern_382_prefixes.insert("http://ddex.net/xml/ern/382".to_string(), "ern".to_string());
43 ern_382_prefixes.insert("http://ddex.net/xml/avs".to_string(), "avs".to_string());
44 ern_382_prefixes.insert("http://ddex.net/xml/avs/avs".to_string(), "avs".to_string());
45 ern_382_prefixes.insert(
46 "http://www.w3.org/2001/XMLSchema-instance".to_string(),
47 "xsi".to_string(),
48 );
49 ern_382_prefixes.insert(
50 "http://www.w3.org/2001/XMLSchema".to_string(),
51 "xs".to_string(),
52 );
53 ern_382_prefixes.insert("http://ddex.net/xml/gc".to_string(), "gc".to_string());
54 self.version_locks
55 .insert("3.8.2".to_string(), ern_382_prefixes.clone());
56 self.version_locks
57 .insert("382".to_string(), ern_382_prefixes);
58
59 let mut ern_42_prefixes = IndexMap::new();
61 ern_42_prefixes.insert("http://ddex.net/xml/ern/42".to_string(), "ern".to_string());
62 ern_42_prefixes.insert("http://ddex.net/xml/avs".to_string(), "avs".to_string());
63 ern_42_prefixes.insert("http://ddex.net/xml/avs/avs".to_string(), "avs".to_string());
64 ern_42_prefixes.insert(
65 "http://www.w3.org/2001/XMLSchema-instance".to_string(),
66 "xsi".to_string(),
67 );
68 ern_42_prefixes.insert(
69 "http://www.w3.org/2001/XMLSchema".to_string(),
70 "xs".to_string(),
71 );
72 ern_42_prefixes.insert("http://ddex.net/xml/gc".to_string(), "gc".to_string());
73 ern_42_prefixes.insert(
75 "http://ddex.net/xml/mead/mead".to_string(),
76 "mead".to_string(),
77 );
78 ern_42_prefixes.insert("http://ddex.net/xml/pie/pie".to_string(), "pie".to_string());
79 self.version_locks
80 .insert("4.2".to_string(), ern_42_prefixes.clone());
81 self.version_locks.insert("42".to_string(), ern_42_prefixes);
82
83 let mut ern_43_prefixes = IndexMap::new();
85 ern_43_prefixes.insert("http://ddex.net/xml/ern/43".to_string(), "ern".to_string());
86 ern_43_prefixes.insert("http://ddex.net/xml/avs".to_string(), "avs".to_string());
87 ern_43_prefixes.insert("http://ddex.net/xml/avs/avs".to_string(), "avs".to_string());
88 ern_43_prefixes.insert(
89 "http://www.w3.org/2001/XMLSchema-instance".to_string(),
90 "xsi".to_string(),
91 );
92 ern_43_prefixes.insert(
93 "http://www.w3.org/2001/XMLSchema".to_string(),
94 "xs".to_string(),
95 );
96 ern_43_prefixes.insert("http://ddex.net/xml/gc".to_string(), "gc".to_string());
97 ern_43_prefixes.insert(
99 "http://ddex.net/xml/mead/mead".to_string(),
100 "mead".to_string(),
101 );
102 ern_43_prefixes.insert("http://ddex.net/xml/pie/pie".to_string(), "pie".to_string());
103 ern_43_prefixes.insert("http://ddex.net/xml/rin/rin".to_string(), "rin".to_string());
104 ern_43_prefixes.insert("http://ddex.net/xml/dsrf".to_string(), "dsrf".to_string());
105 self.version_locks
106 .insert("4.3".to_string(), ern_43_prefixes.clone());
107 self.version_locks.insert("43".to_string(), ern_43_prefixes);
108
109 for prefixes in self.version_locks.values() {
111 for prefix in prefixes.values() {
112 self.reserved_prefixes.insert(prefix.clone());
113 }
114 }
115 }
116
117 pub fn get_locked_prefix(&self, uri: &str, version: &str) -> Option<&str> {
119 self.version_locks
120 .get(version)
121 .and_then(|prefixes| prefixes.get(uri))
122 .map(|prefix| prefix.as_str())
123 }
124
125 pub fn get_version_prefixes(&self, version: &str) -> Option<&IndexMap<String, String>> {
127 self.version_locks.get(version)
128 }
129
130 pub fn deduplicate_prefixes(
132 &self,
133 declarations: &IndexMap<String, String>,
134 version: &str,
135 ) -> IndexMap<String, String> {
136 let mut deduplicated = IndexMap::new();
137 let locked_prefixes = self
138 .get_version_prefixes(version)
139 .cloned()
140 .unwrap_or_default();
141
142 for (original_prefix, uri) in declarations {
144 if let Some(locked_prefix) = locked_prefixes.get(uri) {
145 deduplicated.insert(locked_prefix.clone(), uri.clone());
146 } else {
147 deduplicated.insert(original_prefix.clone(), uri.clone());
149 }
150 }
151
152 let mut final_declarations = IndexMap::new();
154 let mut used_prefixes = HashSet::new();
155
156 for (prefix, uri) in deduplicated {
157 if used_prefixes.contains(&prefix) {
158 let unique_prefix = self.generate_unique_prefix(&prefix, &used_prefixes);
160 used_prefixes.insert(unique_prefix.clone());
161 final_declarations.insert(unique_prefix, uri);
162 } else {
163 used_prefixes.insert(prefix.clone());
164 final_declarations.insert(prefix, uri);
165 }
166 }
167
168 final_declarations
169 }
170
171 fn generate_unique_prefix(&self, base_prefix: &str, used_prefixes: &HashSet<String>) -> String {
173 let mut counter = 1;
174 loop {
175 let candidate = format!("{}{}", base_prefix, counter);
176 if !used_prefixes.contains(&candidate) && !self.reserved_prefixes.contains(&candidate) {
177 return candidate;
178 }
179 counter += 1;
180 }
181 }
182}
183
184pub struct ElementOrder {
186 version_orders: IndexMap<String, IndexMap<String, Vec<String>>>, }
189
190impl ElementOrder {
191 pub fn new() -> Self {
193 let mut order = Self {
194 version_orders: IndexMap::new(),
195 };
196
197 order.initialize_element_orders();
198 order
199 }
200
201 fn initialize_element_orders(&mut self) {
203 let mut ern_382_order = IndexMap::new();
205 self.add_common_orders(&mut ern_382_order);
206 self.add_ern_382_specific_orders(&mut ern_382_order);
207 self.version_orders
208 .insert("3.8.2".to_string(), ern_382_order.clone());
209 self.version_orders.insert("382".to_string(), ern_382_order);
210
211 let mut ern_42_order = IndexMap::new();
213 self.add_common_orders(&mut ern_42_order);
214 self.add_ern_42_specific_orders(&mut ern_42_order);
215 self.version_orders
216 .insert("4.2".to_string(), ern_42_order.clone());
217 self.version_orders.insert("42".to_string(), ern_42_order);
218
219 let mut ern_43_order = IndexMap::new();
221 self.add_common_orders(&mut ern_43_order);
222 self.add_ern_43_specific_orders(&mut ern_43_order);
223 self.version_orders
224 .insert("4.3".to_string(), ern_43_order.clone());
225 self.version_orders.insert("43".to_string(), ern_43_order);
226 }
227
228 fn add_common_orders(&self, order: &mut IndexMap<String, Vec<String>>) {
230 order.insert(
232 "MessageHeader".to_string(),
233 vec![
234 "MessageId".to_string(),
235 "MessageType".to_string(),
236 "MessageCreatedDateTime".to_string(),
237 "MessageSender".to_string(),
238 "MessageRecipient".to_string(),
239 "MessageControlType".to_string(),
240 ],
241 );
242
243 order.insert(
245 "Party".to_string(),
246 vec![
247 "PartyReference".to_string(),
248 "PartyId".to_string(),
249 "PartyName".to_string(),
250 "PartyType".to_string(),
251 ],
252 );
253
254 order.insert(
256 "Release".to_string(),
257 vec![
258 "ReleaseReference".to_string(),
259 "ReleaseId".to_string(),
260 "ReferenceTitle".to_string(),
261 "ReleaseType".to_string(),
262 "ReleaseResourceReferenceList".to_string(),
263 "ReleaseDetailsByTerritory".to_string(),
264 ],
265 );
266
267 order.insert(
269 "Deal".to_string(),
270 vec![
271 "DealReference".to_string(),
272 "DealTerms".to_string(),
273 "DealReleaseReference".to_string(),
274 ],
275 );
276 }
277
278 fn add_ern_382_specific_orders(&self, order: &mut IndexMap<String, Vec<String>>) {
280 order.insert(
282 "SoundRecording".to_string(),
283 vec![
284 "SoundRecordingType".to_string(),
285 "SoundRecordingId".to_string(),
286 "ReferenceTitle".to_string(),
287 "Duration".to_string(),
288 "CreationDate".to_string(),
289 "SoundRecordingDetailsByTerritory".to_string(),
290 ],
291 );
292 }
293
294 fn add_ern_42_specific_orders(&self, order: &mut IndexMap<String, Vec<String>>) {
296 order.insert(
298 "MessageHeader".to_string(),
299 vec![
300 "MessageId".to_string(),
301 "MessageType".to_string(),
302 "MessageCreatedDateTime".to_string(),
303 "MessageSender".to_string(),
304 "MessageRecipient".to_string(),
305 "MessageControlType".to_string(),
306 "MessageAuditTrail".to_string(),
307 ],
308 );
309
310 order.insert(
312 "SoundRecording".to_string(),
313 vec![
314 "SoundRecordingType".to_string(),
315 "SoundRecordingId".to_string(),
316 "ReferenceTitle".to_string(),
317 "DisplayTitle".to_string(),
318 "Duration".to_string(),
319 "CreationDate".to_string(),
320 "MasteredDate".to_string(),
321 "SoundRecordingDetailsByTerritory".to_string(),
322 ],
323 );
324 }
325
326 fn add_ern_43_specific_orders(&self, order: &mut IndexMap<String, Vec<String>>) {
328 order.insert(
330 "MessageHeader".to_string(),
331 vec![
332 "MessageId".to_string(),
333 "MessageType".to_string(),
334 "MessageCreatedDateTime".to_string(),
335 "MessageSender".to_string(),
336 "MessageRecipient".to_string(),
337 "MessageControlType".to_string(),
338 "MessageAuditTrail".to_string(),
339 ],
340 );
341
342 order.insert(
344 "SoundRecording".to_string(),
345 vec![
346 "SoundRecordingType".to_string(),
347 "SoundRecordingId".to_string(),
348 "ReferenceTitle".to_string(),
349 "DisplayTitle".to_string(),
350 "DisplayTitleText".to_string(),
351 "Duration".to_string(),
352 "CreationDate".to_string(),
353 "MasteredDate".to_string(),
354 "OriginalResourceReleaseDate".to_string(),
355 "SoundRecordingDetailsByTerritory".to_string(),
356 ],
357 );
358
359 order.insert(
361 "Video".to_string(),
362 vec![
363 "VideoType".to_string(),
364 "VideoId".to_string(),
365 "ReferenceTitle".to_string(),
366 "DisplayTitle".to_string(),
367 "Duration".to_string(),
368 "CreationDate".to_string(),
369 "VideoDetailsByTerritory".to_string(),
370 ],
371 );
372
373 order.insert(
375 "Image".to_string(),
376 vec![
377 "ImageType".to_string(),
378 "ImageId".to_string(),
379 "ReferenceTitle".to_string(),
380 "DisplayTitle".to_string(),
381 "CreationDate".to_string(),
382 "ImageDetailsByTerritory".to_string(),
383 ],
384 );
385 }
386
387 pub fn get_element_order(&self, parent_element: &str, version: &str) -> Option<&Vec<String>> {
389 self.version_orders
390 .get(version)
391 .and_then(|orders| orders.get(parent_element))
392 }
393
394 pub fn get_version_orders(&self, version: &str) -> Option<&IndexMap<String, Vec<String>>> {
396 self.version_orders.get(version)
397 }
398}
399
400pub struct AVSNamespaceHandler {
402 avs_namespaces: IndexMap<String, String>,
404}
405
406impl AVSNamespaceHandler {
407 pub fn new() -> Self {
409 let mut handler = Self {
410 avs_namespaces: IndexMap::new(),
411 };
412
413 handler
415 .avs_namespaces
416 .insert("http://ddex.net/xml/avs".to_string(), "avs".to_string());
417 handler
418 .avs_namespaces
419 .insert("http://ddex.net/xml/avs/avs".to_string(), "avs".to_string());
420
421 handler
422 }
423
424 pub fn is_avs_namespace(&self, uri: &str) -> bool {
426 self.avs_namespaces.contains_key(uri)
427 }
428
429 pub fn get_avs_prefix(&self, uri: &str) -> Option<&str> {
431 self.avs_namespaces.get(uri).map(|prefix| prefix.as_str())
432 }
433}
434
435pub struct CanonicalNamespaceManager {
437 prefix_lock: NamespacePrefixLock,
439 element_order: ElementOrder,
441 avs_handler: AVSNamespaceHandler,
443}
444
445impl CanonicalNamespaceManager {
446 pub fn new() -> Self {
448 Self {
449 prefix_lock: NamespacePrefixLock::new(),
450 element_order: ElementOrder::new(),
451 avs_handler: AVSNamespaceHandler::new(),
452 }
453 }
454
455 pub fn canonicalize_namespaces(
457 &self,
458 declarations: &IndexMap<String, String>,
459 version: &str,
460 ) -> IndexMap<String, String> {
461 let locked_declarations = self.prefix_lock.deduplicate_prefixes(declarations, version);
463
464 let mut sorted_declarations: Vec<_> = locked_declarations.into_iter().collect();
466 sorted_declarations.sort_by(|a, b| a.0.cmp(&b.0));
467
468 sorted_declarations.into_iter().collect()
469 }
470
471 pub fn get_canonical_element_order(&self, parent: &str, version: &str) -> Option<&Vec<String>> {
473 self.element_order.get_element_order(parent, version)
474 }
475
476 pub fn requires_avs_handling(&self, uri: &str) -> bool {
478 self.avs_handler.is_avs_namespace(uri)
479 }
480}
481
482impl Default for NamespacePrefixLock {
483 fn default() -> Self {
484 Self::new()
485 }
486}
487
488impl Default for ElementOrder {
489 fn default() -> Self {
490 Self::new()
491 }
492}
493
494impl Default for AVSNamespaceHandler {
495 fn default() -> Self {
496 Self::new()
497 }
498}
499
500impl Default for CanonicalNamespaceManager {
501 fn default() -> Self {
502 Self::new()
503 }
504}
505
506pub fn get_namespace_prefixes(version: &str) -> IndexMap<String, String> {
510 let lock = NamespacePrefixLock::new();
511 lock.get_version_prefixes(version)
512 .cloned()
513 .unwrap_or_default()
514}
515
516pub fn get_element_order(version: &str) -> IndexMap<String, Vec<String>> {
518 let order = ElementOrder::new();
519 order
520 .get_version_orders(version)
521 .cloned()
522 .unwrap_or_default()
523}
524
525#[cfg(test)]
526mod tests {
527 use super::*;
528
529 #[test]
530 fn test_namespace_prefix_lock() {
531 let lock = NamespacePrefixLock::new();
532
533 assert_eq!(
534 lock.get_locked_prefix("http://ddex.net/xml/ern/43", "4.3"),
535 Some("ern")
536 );
537 assert_eq!(
538 lock.get_locked_prefix("http://ddex.net/xml/avs", "4.3"),
539 Some("avs")
540 );
541 }
542
543 #[test]
544 fn test_prefix_deduplication() {
545 let lock = NamespacePrefixLock::new();
546
547 let mut declarations = IndexMap::new();
548 declarations.insert(
549 "custom_ern".to_string(),
550 "http://ddex.net/xml/ern/43".to_string(),
551 );
552 declarations.insert("avs".to_string(), "http://ddex.net/xml/avs".to_string());
553
554 let deduplicated = lock.deduplicate_prefixes(&declarations, "4.3");
555
556 assert_eq!(
558 deduplicated.get("ern"),
559 Some(&"http://ddex.net/xml/ern/43".to_string())
560 );
561 assert_eq!(
562 deduplicated.get("avs"),
563 Some(&"http://ddex.net/xml/avs".to_string())
564 );
565 }
566
567 #[test]
568 fn test_element_order() {
569 let order = ElementOrder::new();
570
571 let message_order = order.get_element_order("MessageHeader", "4.3");
572 assert!(message_order.is_some());
573
574 let order_vec = message_order.unwrap();
575 assert_eq!(order_vec[0], "MessageId");
576 assert_eq!(order_vec[1], "MessageType");
577 }
578
579 #[test]
580 fn test_avs_namespace_handler() {
581 let handler = AVSNamespaceHandler::new();
582
583 assert!(handler.is_avs_namespace("http://ddex.net/xml/avs"));
584 assert_eq!(
585 handler.get_avs_prefix("http://ddex.net/xml/avs"),
586 Some("avs")
587 );
588 assert!(!handler.is_avs_namespace("http://ddex.net/xml/ern/43"));
589 }
590
591 #[test]
592 fn test_canonical_namespace_manager() {
593 let manager = CanonicalNamespaceManager::new();
594
595 let mut declarations = IndexMap::new();
596 declarations.insert(
597 "z_ern".to_string(),
598 "http://ddex.net/xml/ern/43".to_string(),
599 );
600 declarations.insert("a_avs".to_string(), "http://ddex.net/xml/avs".to_string());
601
602 let canonical = manager.canonicalize_namespaces(&declarations, "4.3");
603
604 let keys: Vec<_> = canonical.keys().collect();
606 assert!(keys.len() >= 2);
607 assert!(canonical.contains_key("ern"));
609 assert!(canonical.contains_key("avs"));
610 }
611}