You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Rust的quick_xml读取XML文件并实时打印读取事件?

用quick_xml实现统一格式的事件生成器

先定义统一的事件结构,把quick_xml的原生事件转换成你需要的(事件类型, 标签, 属性, 文本)格式:

use quick_xml::Reader;
use quick_xml::events::{Event, BytesStart, BytesEnd};
use std::io::BufRead;

// 定义事件类型枚举
#[derive(Debug)]
enum EventType {
    Start,
    End,
    Text,
    Eof,
}

// 统一格式的事件结构体
#[derive(Debug)]
struct ParsedEvent {
    event_type: EventType,
    tag: Option<String>,
    attributes: Vec<String>,
    text: Option<String>,
}

接下来实现生成器函数,读取XML事件并完成格式转换,同时处理文本分段的问题(XML文本可能被拆成多个Text事件):

fn xml_event_generator<R: BufRead>(mut reader: Reader<R>) -> impl Iterator<Item = ParsedEvent> {
    let mut buf = Vec::new();
    let mut accumulated_text = String::new();

    std::iter::from_fn(move || {
        buf.clear();
        match reader.read_event_into(&mut buf) {
            Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
            Ok(Event::Eof) => {
                // 输出剩余的累积文本
                let text_event = if !accumulated_text.is_empty() {
                    let text = accumulated_text.clone();
                    accumulated_text.clear();
                    Some(ParsedEvent {
                        event_type: EventType::Text,
                        tag: None,
                        attributes: vec![],
                        text: Some(text),
                    })
                } else {
                    None
                };
                // 最后返回Eof事件
                text_event.or_else(|| Some(ParsedEvent {
                    event_type: EventType::Eof,
                    tag: None,
                    attributes: vec![],
                    text: None,
                }))
            }
            Ok(Event::Start(e)) => {
                // 先输出之前累积的文本
                let text_event = if !accumulated_text.is_empty() {
                    let text = accumulated_text.clone();
                    accumulated_text.clear();
                    Some(ParsedEvent {
                        event_type: EventType::Text,
                        tag: None,
                        attributes: vec![],
                        text: Some(text),
                    })
                } else {
                    None
                };

                text_event.or_else(|| {
                    // 转换Start事件格式
                    let tag = e.name().local_name().to_string_lossy().into_owned();
                    let attributes = e.attributes()
                        .filter_map(|a| a.ok())
                        .map(|a| a.value.to_string_lossy().into_owned())
                        .collect();
                    Some(ParsedEvent {
                        event_type: EventType::Start,
                        tag: Some(tag),
                        attributes,
                        text: None,
                    })
                })
            }
            Ok(Event::Text(e)) => {
                // 累积文本(处理转义)
                if let Ok(unescaped) = e.unescape() {
                    accumulated_text.push_str(&unescaped.into_owned());
                }
                // 继续读取下一个事件,暂不返回文本
                xml_event_generator(reader).next()
            }
            Ok(Event::End(e)) => {
                // 先输出累积的文本
                let text_event = if !accumulated_text.is_empty() {
                    let text = accumulated_text.clone();
                    accumulated_text.clear();
                    Some(ParsedEvent {
                        event_type: EventType::Text,
                        tag: None,
                        attributes: vec![],
                        text: Some(text),
                    })
                } else {
                    None
                };

                text_event.or_else(|| {
                    // 转换End事件格式
                    let tag = e.name().local_name().to_string_lossy().into_owned();
                    Some(ParsedEvent {
                        event_type: EventType::End,
                        tag: Some(tag),
                        attributes: vec![],
                        text: None,
                    })
                })
            }
            // 忽略注释、CData等其他事件
            _ => xml_event_generator(reader).next(),
        }
    })
}

用法示例

fn main() {
    let xml = r#"<root attr="test"><item>Hello <bold>World</bold></item></root>"#;
    let reader = Reader::from_str(xml);
    let mut generator = xml_event_generator(reader);

    while let Some(event) = generator.next() {
        match event.event_type {
            EventType::Start => println!("(start, {:?}, {:?}, None)", event.tag.unwrap(), event.attributes),
            EventType::End => println!("(end, {:?}, [], None)", event.tag.unwrap()),
            EventType::Text => println!("(text, None, [], {:?})", event.text.unwrap()),
            EventType::Eof => break,
        }
    }
}

关键细节

  • 文本累积:解决XML文本被拆分为多个Text事件的问题,确保输出完整的元素文本
  • 格式统一:所有事件都通过ParsedEvent结构体标准化,方便后续处理
  • 错误处理:示例中直接panic,实际项目可改为返回Result类型,符合Rust错误处理规范

后续PyO3集成提示

可以用PyO3把ParsedEvent转换成Python字典或自定义类,再通过PyO3的生成器API(比如结合PyIter)暴露给Python使用,就能实现Rust解析XML,Python消费事件的流程。

内容的提问来源于stack exchange,提问作者safetyduck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 10:41:17