【问题标题】:How can I parse a Vec<String> of individual lines as XML in Rust?如何在 Rust 中将单个行的 Vec<String> 解析为 XML?
【发布时间】:2020-10-02 17:13:57
【问题描述】:

我正在编写一个 Rust 命令行程序来 grep 日志文件。它逐行读取输入文件,并创建包含“基本”日志行(带有时间戳、日志级别、线程名称、类名等)和“额外”日志行(包含嵌入式 XML 或 JSON 消息)的记录。这是一个简化的示例:

(preceding line)
[2020-10-02 12:00:00,000Z][INFO][input-io][XMLReader] Received XML message:
<?xml version="1.0"?>
<Outer foo="bar"><Inner baz="qux"/></Outer>
(following line)

我已经到了尝试为单个记录漂亮地打印嵌入式 XML 消息的地步。我需要做的是获取“额外的”日志行(存储在 Vec&lt;String&gt; 中)并将它们传递给 XML 拉式阅读器库之一(我目前正在查看 quick_xml,因为它在基准测试中表现良好,但是如有必要,我会使用不同的)。

我的问题是 quick_xml Reader 类需要 BufRead 实现,但我不知道如何从 Vec&lt;String&gt; 创建它。谁能给点建议?

另外,一些其他语言的 XML 拉式阅读器库支持以任意块的形式提供文本。有没有这样的 XML 库?

【问题讨论】:

    标签: rust


    【解决方案1】:

    您可以使用Vec::join 将所有行合并为一个:

    use quick_xml::Reader;
    use quick_xml::events::Event;
    
    fn main() {
        let vec_of_string = vec![
            "<?xml version=\"1.0\"?>".to_owned(),
            "<Outer foo=\"bar\">".to_owned(),
            "<Inner baz=\"qux\"/>".to_owned(),
            "</Outer>".to_owned(),
        ];
     
        // HERE WE GO   
        let xml = vec_of_string.join("\n");
        
        // copy-paste from quick_xml's documentation
        let mut reader = Reader::from_str(&xml);
        let mut buf = Vec::new();
        loop {
            match reader.read_event(&mut buf) {
                Ok(Event::Start(ref e)) => {
                    println!(
                        "name:{:?} attributes values:{:?}", 
                        e.name(),
                        e.attributes()
                            .map(|a| a.unwrap().value)
                            .collect::<Vec<_>>()
                    );
                },
                Ok(Event::Eof) => break,
                Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
                _ => (),
            }
    
            buf.clear();
        }
    }
    

    【讨论】:

    • 看起来 join() 调用的结果是 owned 数据,因此被复制,因为我可以在比原始向量更广泛的范围内引用它.我希望能够一次将源数据输入到拉解析器中(而不必复制它),但如果这是我的选择,我会接受它;谢谢!
    【解决方案2】:

    您可以尝试为您的字符串 Vec 实现 BufRead trait。 但是,您需要克服 Orphan Rule,因为您并不同时拥有 Vec 类型和 BufRead trait。

    所以你需要使用包装类型:

    struct BufReadVecWrapper{
       // You can use reference to slice of strings 
       // if you want to preserve your vec
       strings: Vec<String>, 
    }
    
    impl BufRead for BufReadVecWrapper{
       // Implement all methods here
       // basically, you just send bytes of your strings here
    }
    
    let wrapper = BufReadVecWrapper{strings: your_vec};
    let mut reader = quick_xml::Reader::from_reader(wrapper);
    

    您现在可以像在MaxV's answer 中一样使用阅读器,并避免在将所有字符串合并为一个时进行额外分配。但是,这将需要更多的努力。

    【讨论】:

    • 谢谢,值得一试。但是,鉴于我的用例非常有限,并且不需要功能齐全的 XML 解析器,我决定屈服于狂妄自大并编写自己的(我还需要一个具有类似要求的 JSON 解析器)。鉴于它将定义一个 feed() 函数,接受一个字符串引用和一个回调特征的 impl,它应该需要零分配。
    猜你喜欢
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 2021-03-16
    相关资源
    最近更新 更多