quick-xml解析XML在rust中高效,事件驱动(Reader)适合流式/大文件,结构化反序列化(de::from_str)适合已知结构;需按需启用features,注意编码、命名匹配与内存控制。

用 quick-xml 解析 XML 在 Rust 中很高效,核心是选择合适的 API 模式:事件驱动(Reader)适合流式、大文件或自定义逻辑;结构化反序列化(de::from_str)适合已知结构、追求简洁。
快速上手:用 Reader 做事件驱动解析
quick-xml 的 Reader 类型以迭代方式暴露 XML 事件(开始标签、文本、结束标签等),内存占用低,控制粒度细。
- 添加依赖到
Cargo.toml:quick-xml = { version = "0.32", features = ["encoding"] } - 基础读取示例(跳过空白、提取所有
<item></item>的name文本):
use quick_xml::events::BytesStart; use quick_xml::Reader; let xml = r#" <root> <item id="1"><name>apple</name></item> <item id="2"><name>Banana</name></item> </root>"#; let mut reader = Reader::from_str(xml); reader.trim_text(true); // 自动忽略纯空白文本节点 let mut buf = Vec::new(); let mut names = Vec::new(); loop { match reader.read_event_into(&mut buf) { Ok(quick_xml::events::BytesEvent::Start(ref e)) if e.name().as_ref() == b"name" => { // 下一个事件应为 Text match reader.read_event_into(&mut buf) { Ok(quick_xml::events::BytesEvent::Text(e)) => { names.push(e.unescape_and_decode(&reader).unwrap_or_default()); } _ => {} } } Ok(quick_xml::events::BytesEvent::Eof) => break, _ => {} } buf.clear(); } // names == ["apple", "Banana"]
结构化解析:用 serde 反序列化成 Rust 结构体
如果你的 XML 格式固定,推荐用 serde + quick-xml 的 de::from_str,写法接近 jsON 解析,更直观。
- 启用
serde功能:quick-xml = { version = "0.32", features = ["serialize"] } - 定义结构体并标注
#[derive(Deserialize)],注意字段名与 XML 标签名/属性名匹配:
use serde::Deserialize; #[derive(Deserialize, Debug)] struct Item { #[serde(rename = "@id")] // @ 表示属性 id: u32, name: String, } #[derive(Deserialize, Debug)] struct Root { #[serde(rename = "item")] items: Vec<Item>, } let xml = r#" <root> <item id="1"><name>Apple</name></item> <item id="2"><name>Banana</name></item> </root>"#; let root: Root = quick_xml::de::from_str(xml).unwrap(); // root.items[0].id == 1, root.items[0].name == "Apple"
处理命名空间和 CDATA
默认情况下 quick-xml 不自动解析命名空间前缀,需手动配置 Reader::with_config 启用;CDATA 内容会被当作普通文本,但可通过 BytesEvent::CData 事件单独捕获。
- 启用命名空间支持(需开启
features = ["encoding", "namespaces"]): let mut reader = Reader::from_str(xml).with_config(ReaderConfig::default().trim_text(true).check_namespace(true));- 识别 CDATA:
在read_event_into循环中匹配BytesEvent::CData(e),然后用e.unescape_and_decode(&reader)获取内容。
常见陷阱与建议
避免运行时 panic 或解析失败,注意以下几点: