Skip to main content

wx_rust_common/util/
xml_utils.rs

1//! XML 转换工具类。
2//!
3//! 对应 Java `me.chanjar.weixin.common.util.XmlUtils`(基于 dom4j 的 xml2Map)。
4//! Rust 侧使用 `quick-xml` 实现相同语义:XML → `Map<String, Object>`。
5
6use std::collections::HashMap;
7
8use quick_xml::Reader;
9use quick_xml::XmlVersion;
10use quick_xml::events::Event;
11
12/// XML 转换工具。
13pub struct XmlUtils;
14
15impl XmlUtils {
16    /// 将 XML 字符串转换为键值 Map。
17    ///
18    /// 语义与 Java `xml2Map` 一致:顶层元素下的每个子元素作为键,
19    /// 元素文本作为值;同名元素保留最后一个(Java 实现用 HashMap)。
20    ///
21    /// # 参数
22    /// - `xml_string`:XML 字符串
23    ///
24    /// # 返回
25    /// 键值 Map;解析失败时返回错误。
26    pub fn xml_2_map(xml_string: &str) -> Result<HashMap<String, String>, String> {
27        let mut reader = Reader::from_str(xml_string);
28        reader.config_mut().trim_text(true);
29
30        let mut map = HashMap::new();
31        let mut depth = 0usize;
32        let mut current_tag: Option<String> = None;
33        let mut buf = Vec::new();
34
35        loop {
36            match reader.read_event_into(&mut buf) {
37                Ok(Event::Start(e)) => {
38                    depth += 1;
39                    if depth == 2 {
40                        current_tag = Some(e.name().as_ref().to_string());
41                    }
42                }
43                Ok(Event::Text(t)) => {
44                    if let Some(tag) = &current_tag {
45                        let text = t.xml_content(XmlVersion::Implicit1_0).to_string();
46                        map.insert(tag.clone(), text);
47                    }
48                }
49                Ok(Event::CData(t)) => {
50                    if let Some(tag) = &current_tag {
51                        let text = t.xml_content(XmlVersion::Implicit1_0).to_string();
52                        map.insert(tag.clone(), text);
53                    }
54                }
55                Ok(Event::End(_)) => {
56                    if depth >= 2 {
57                        depth -= 1;
58                        if depth == 1 {
59                            current_tag = None;
60                        }
61                    }
62                }
63                Ok(Event::Eof) => break,
64                Err(e) => return Err(format!("XML 解析失败: {e}")),
65                _ => {}
66            }
67            buf.clear();
68        }
69        Ok(map)
70    }
71}