easyofd_reader/tools/
namespace_cleaner.rs1#[derive(Debug, Clone, Copy)]
14pub struct NamespaceCleaner;
15
16impl NamespaceCleaner {
17 #[must_use]
21 pub fn remove_prefix(xml: &str, prefix: &str) -> String {
22 let with_colon = format!("{prefix}:");
23 xml.replace(&with_colon, "")
24 }
25
26 #[must_use]
28 pub fn remove_ofd_prefix(xml: &str) -> String {
29 Self::remove_prefix(xml, "ofd")
30 }
31
32 #[must_use]
36 pub fn remove_namespace_declarations(xml: &str) -> String {
37 let mut result = String::with_capacity(xml.len());
38 let mut remaining = xml;
39
40 while let Some(start) = remaining.find("xmlns:") {
41 result.push_str(&remaining[..start]);
42 let after_attr = &remaining[start..];
44 if let Some(eq_pos) = after_attr.find('=').map(|p| p + 1) {
45 let after_eq = &after_attr[eq_pos..];
46 if let Some(quote_end) = find_closing_quote(after_eq) {
48 remaining = &after_eq[quote_end + 1..];
49 } else {
50 result.push_str(after_attr);
52 break;
53 }
54 } else {
55 result.push_str(after_attr);
56 break;
57 }
58 }
59 result.push_str(remaining);
60 result
61 }
62}
63
64fn find_closing_quote(s: &str) -> Option<usize> {
66 let s = s.trim_start();
67 let quote_char = s.as_bytes().first()?;
68 if *quote_char != b'"' && *quote_char != b'\'' {
69 return None;
70 }
71 let content = &s[1..];
72 content
73 .find(*quote_char as char)
74 .map(|pos| pos + 1 + (s.len() - content.len()))
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn test_remove_ofd_prefix() {
83 let xml = "<ofd:OFD><ofd:DocBody><ofd:DocRoot/></ofd:DocBody></ofd:OFD>";
84 let result = NamespaceCleaner::remove_ofd_prefix(xml);
85 assert!(!result.contains("ofd:"));
86 assert!(result.contains("<OFD>"));
87 assert!(result.contains("<DocBody>"));
88 assert!(result.contains("<DocRoot/>"));
89 assert!(result.contains("</OFD>"));
90 }
91
92 #[test]
93 fn test_remove_custom_prefix() {
94 let xml = "<ns:Root><ns:Child/></ns:Root>";
95 let result = NamespaceCleaner::remove_prefix(xml, "ns");
96 assert_eq!(result, "<Root><Child/></Root>");
97 }
98
99 #[test]
100 fn test_remove_namespace_declarations() {
101 let xml =
102 r#"<ofd:OFD xmlns:ofd="http://www.ofdspec.org/2016" xmlns:custom="http://custom">"#;
103 let result = NamespaceCleaner::remove_namespace_declarations(xml);
104 assert!(!result.contains("xmlns:ofd"));
105 assert!(!result.contains("xmlns:custom"));
106 assert!(result.contains("<ofd:OFD"));
107 }
108
109 #[test]
110 fn test_no_prefix() {
111 let xml = "<Root><Child/></Root>";
112 let result = NamespaceCleaner::remove_ofd_prefix(xml);
113 assert_eq!(result, xml);
114 }
115
116 #[test]
117 fn test_empty_xml() {
118 let result = NamespaceCleaner::remove_ofd_prefix("");
119 assert!(result.is_empty());
120 }
121}