1use crate::context::ErrorContext;
5use crate::error::{ OfficeError, Result };
6use quick_xml::events::{ BytesEnd, BytesStart, BytesText, Event };
7use quick_xml::{ Reader, Writer };
8use std::collections::HashMap;
9use std::io::{ BufRead, Write };
10
11#[derive(Debug, Clone)]
13pub struct NamespaceManager {
14 namespaces: HashMap<String, String>,
15 default_namespace: Option<String>,
16}
17
18impl NamespaceManager {
19 pub fn new() -> Self {
21 Self {
22 namespaces: HashMap::new(),
23 default_namespace: None,
24 }
25 }
26
27 pub fn add_namespace(&mut self, prefix: String, uri: String) {
29 self.namespaces.insert(prefix, uri);
30 }
31
32 pub fn set_default_namespace(&mut self, uri: String) {
34 self.default_namespace = Some(uri);
35 }
36
37 pub fn get_namespace_uri(&self, prefix: &str) -> Option<&String> {
39 self.namespaces.get(prefix)
40 }
41
42 pub fn parse_qualified_name<'a>(&self, name: &'a str) -> (Option<&String>, &'a str) {
44 if let Some(colon_pos) = name.find(':') {
45 let prefix = &name[..colon_pos];
46 let local_name = &name[colon_pos + 1..];
47 (self.get_namespace_uri(prefix), local_name)
48 } else {
49 (self.default_namespace.as_ref(), name)
50 }
51 }
52}
53
54#[derive(Debug, Clone)]
56pub struct XmlElement {
57 pub name: String,
58 pub attributes: HashMap<String, String>,
59 pub text_content: Option<String>,
60 pub children: Vec<XmlElement>,
61}
62
63impl XmlElement {
64 pub fn new<S: AsRef<str>>(name: S) -> Self {
66 Self {
67 name: name.as_ref().to_string(),
68 attributes: HashMap::new(),
69 text_content: None,
70 children: Vec::new(),
71 }
72 }
73
74 pub fn add_attribute<K: AsRef<str>, V: AsRef<str>>(&mut self, name: K, value: V) {
76 self.attributes.insert(name.as_ref().to_string(), value.as_ref().to_string());
77 }
78
79 pub fn get_attribute(&self, name: &str) -> Option<&String> {
81 self.attributes.get(name)
82 }
83
84 pub fn set_text_content<S: AsRef<str>>(&mut self, content: S) {
86 self.text_content = Some(content.as_ref().to_string());
87 }
88
89 pub fn add_child(&mut self, child: XmlElement) {
91 self.children.push(child);
92 }
93
94 pub fn find_child(&self, name: &str) -> Option<&XmlElement> {
96 self.children.iter().find(|child| child.name == name)
97 }
98
99 pub fn find_children(&self, name: &str) -> Vec<&XmlElement> {
101 self.children
102 .iter()
103 .filter(|child| child.name == name)
104 .collect()
105 }
106
107 pub fn find_element_recursive(&self, name: &str) -> Option<&XmlElement> {
109 if self.name == name {
110 return Some(self);
111 }
112
113 for child in &self.children {
114 if let Some(found) = child.find_element_recursive(name) {
115 return Some(found);
116 }
117 }
118
119 None
120 }
121}
122
123pub struct XmlParser {
125 namespace_manager: NamespaceManager,
126}
127
128impl XmlParser {
129 pub fn new() -> Self {
131 Self {
132 namespace_manager: NamespaceManager::new(),
133 }
134 }
135
136 pub fn add_namespace(&mut self, prefix: String, uri: String) {
138 self.namespace_manager.add_namespace(prefix, uri);
139 }
140
141 pub fn parse_string(&self, xml_content: &str) -> Result<XmlElement> {
143 let mut reader = Reader::from_str(xml_content);
144 reader.config_mut().trim_text(true);
145
146 let context = ErrorContext {
147 operation: Some("解析XML字符串".to_string()),
148 ..Default::default()
149 };
150
151 self.parse_element(&mut reader, &context)
152 }
153
154 pub fn parse_bytes(&self, xml_bytes: &[u8]) -> Result<XmlElement> {
156 let mut reader = Reader::from_reader(xml_bytes);
157 reader.config_mut().trim_text(true);
158
159 let context = ErrorContext {
160 operation: Some("解析XML字节流".to_string()),
161 ..Default::default()
162 };
163
164 self.parse_element(&mut reader, &context)
165 }
166
167 fn parse_element<R: BufRead>(
169 &self,
170 reader: &mut Reader<R>,
171 context: &ErrorContext
172 ) -> Result<XmlElement> {
173 let mut buf = Vec::new();
174 let mut element_stack: Vec<XmlElement> = Vec::new();
175 let mut root_element: Option<XmlElement> = None;
176
177 loop {
178 match reader.read_event_into(&mut buf) {
179 Ok(Event::Start(ref e)) => {
180 let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
181 let mut element = XmlElement::new(name);
182
183 for attr in e.attributes() {
185 let attr = attr.map_err(|e| {
186 OfficeError::Xml(quick_xml::Error::InvalidAttr(e)).with_context(
187 context.clone()
188 )
189 })?;
190 let key = String::from_utf8_lossy(attr.key.as_ref()).to_string();
191 let value = String::from_utf8_lossy(&attr.value).to_string();
192 element.add_attribute(key, value);
193 }
194
195 element_stack.push(element);
196 }
197 Ok(Event::End(_)) => {
198 if let Some(element) = element_stack.pop() {
199 if let Some(parent) = element_stack.last_mut() {
200 parent.add_child(element);
201 } else {
202 root_element = Some(element);
203 break;
204 }
205 }
206 }
207 Ok(Event::Text(ref e)) => {
208 let text = std::str::from_utf8(e.as_ref()).unwrap_or("");
209 if let Some(element) = element_stack.last_mut() {
210 element.set_text_content(text.to_string());
211 }
212 }
213 Ok(Event::Empty(ref e)) => {
214 let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
215 let mut element = XmlElement::new(name);
216
217 for attr in e.attributes() {
219 let attr = attr.map_err(|e| {
220 OfficeError::Xml(quick_xml::Error::InvalidAttr(e)).with_context(
221 context.clone()
222 )
223 })?;
224 let key = String::from_utf8_lossy(attr.key.as_ref()).to_string();
225 let value = String::from_utf8_lossy(&attr.value).to_string();
226 element.add_attribute(key, value);
227 }
228
229 if let Some(parent) = element_stack.last_mut() {
230 parent.add_child(element);
231 } else {
232 root_element = Some(element);
233 break;
234 }
235 }
236 Ok(Event::Eof) => {
237 break;
238 }
239 Err(e) => {
240 return Err(OfficeError::Xml(e).with_context(context.clone()));
241 }
242 _ => {} }
244 buf.clear();
245 }
246
247 root_element.ok_or_else(|| {
248 OfficeError::parse_error_with_context("root".to_string(), context.clone())
249 })
250 }
251}
252
253pub struct XmlGenerator {
255 namespace_manager: NamespaceManager,
256}
257
258impl XmlGenerator {
259 pub fn new() -> Self {
261 Self {
262 namespace_manager: NamespaceManager::new(),
263 }
264 }
265
266 pub fn add_namespace(&mut self, prefix: String, uri: String) {
268 self.namespace_manager.add_namespace(prefix, uri);
269 }
270
271 pub fn generate_string(&self, element: &XmlElement) -> Result<String> {
273 let mut output = Vec::new();
274 {
275 let mut writer = Writer::new(&mut output);
276 self.write_element(&mut writer, element)?;
277 }
278
279 String::from_utf8(output).map_err(|e| OfficeError::Other(format!("UTF-8编码错误: {}", e)))
280 }
281
282 pub fn write_element<W: Write>(
284 &self,
285 writer: &mut Writer<W>,
286 element: &XmlElement
287 ) -> Result<()> {
288 let context = ErrorContext {
289 operation: Some("生成XML".to_string()),
290 ..Default::default()
291 };
292
293 let mut start_tag = BytesStart::new(&element.name);
295
296 for (key, value) in &element.attributes {
298 start_tag.push_attribute((key.as_str(), value.as_str()));
299 }
300
301 if element.children.is_empty() && element.text_content.is_none() {
302 writer
304 .write_event(Event::Empty(start_tag))
305 .map_err(|e| OfficeError::Xml(e.into()).with_context(context.clone()))?;
306 } else {
307 writer
309 .write_event(Event::Start(start_tag))
310 .map_err(|e| OfficeError::Xml(e.into()).with_context(context.clone()))?;
311
312 if let Some(text) = &element.text_content {
314 writer
315 .write_event(Event::Text(BytesText::new(text)))
316 .map_err(|e| OfficeError::Xml(e.into()).with_context(context.clone()))?;
317 }
318
319 for child in &element.children {
321 self.write_element(writer, child)?;
322 }
323
324 writer
326 .write_event(Event::End(BytesEnd::new(&element.name)))
327 .map_err(|e| OfficeError::Xml(e.into()).with_context(context.clone()))?;
328 }
329
330 Ok(())
331 }
332}
333
334pub mod utils {
336 use super::*;
337
338 pub fn escape_xml(text: &str) -> String {
340 text.replace('&', "&")
341 .replace('<', "<")
342 .replace('>', ">")
343 .replace('"', """)
344 .replace('\'', "'")
345 }
346
347 pub fn unescape_xml(text: &str) -> String {
349 text.replace("&", "&")
350 .replace("<", "<")
351 .replace(">", ">")
352 .replace(""", "\"")
353 .replace("'", "'")
354 }
355
356 pub fn is_valid_xml_name(name: &str) -> bool {
358 if name.is_empty() {
359 return false;
360 }
361
362 let first_char = name.chars().next().unwrap();
363 if !first_char.is_alphabetic() && first_char != '_' {
364 return false;
365 }
366
367 name.chars().all(|c| (c.is_alphanumeric() || c == '_' || c == '-' || c == '.'))
368 }
369
370 pub fn format_xml(xml: &str, indent: &str) -> Result<String> {
372 let parser = XmlParser::new();
373 let element = parser.parse_string(xml)?;
374
375 let mut result = String::new();
376 format_element(&element, &mut result, indent, 0);
377 Ok(result)
378 }
379
380 fn format_element(element: &XmlElement, result: &mut String, indent: &str, level: usize) {
381 let current_indent = indent.repeat(level);
382
383 result.push_str(¤t_indent);
385 result.push('<');
386 result.push_str(&element.name);
387
388 for (key, value) in &element.attributes {
390 result.push_str(&format!(" {}=\"{}\"", key, escape_xml(value)));
391 }
392
393 if element.children.is_empty() && element.text_content.is_none() {
394 result.push_str("/>\n");
395 } else {
396 result.push_str(">\n");
397
398 if let Some(text) = &element.text_content {
400 result.push_str(&indent.repeat(level + 1));
401 result.push_str(&escape_xml(text));
402 result.push('\n');
403 }
404
405 for child in &element.children {
407 format_element(child, result, indent, level + 1);
408 }
409
410 result.push_str(¤t_indent);
412 result.push_str(&format!("</{}>", element.name));
413 result.push('\n');
414 }
415 }
416}
417
418#[cfg(test)]
419mod tests {
420 use super::*;
421
422 #[test]
423 fn test_namespace_manager() {
424 let mut ns_mgr = NamespaceManager::new();
425 ns_mgr.add_namespace(
426 "w".to_string(),
427 "http://schemas.openxmlformats.org/wordprocessingml/2006/main".to_string()
428 );
429
430 let (ns_uri, local_name) = ns_mgr.parse_qualified_name("w:document");
431 assert_eq!(local_name, "document");
432 assert!(ns_uri.is_some());
433 }
434
435 #[test]
436 fn test_xml_parsing() {
437 let xml = r#"<root attr="value"><child>text</child></root>"#;
438 let parser = XmlParser::new();
439 let element = parser.parse_string(xml).unwrap();
440
441 assert_eq!(element.name, "root");
442 assert_eq!(element.get_attribute("attr"), Some(&"value".to_string()));
443 assert_eq!(element.children.len(), 1);
444 assert_eq!(element.children[0].name, "child");
445 assert_eq!(element.children[0].text_content, Some("text".to_string()));
446 }
447
448 #[test]
449 fn test_xml_generation() {
450 let mut element = XmlElement::new("root");
451 element.add_attribute("attr", "value");
452
453 let mut child = XmlElement::new("child");
454 child.set_text_content("text");
455 element.add_child(child);
456
457 let generator = XmlGenerator::new();
458 let xml = generator.generate_string(&element).unwrap();
459
460 assert!(xml.contains("<root attr=\"value\">"));
461 assert!(xml.contains("<child>text</child>"));
462 assert!(xml.contains("</root>"));
463 }
464}