tihu_native/
xml.rs

1use quick_xml::events::Event;
2use quick_xml::reader::Reader;
3use std::collections::HashMap;
4use std::io::BufRead;
5use std::io::Read;
6
7#[derive(Debug)]
8
9pub struct Node {
10    pub name: String,
11    pub attributes: HashMap<String, String>,
12    pub children: Vec<Child>,
13}
14
15#[derive(Debug)]
16pub enum Child {
17    Node(Node),
18    Text(String),
19}
20
21fn parse_children<R>(
22    reader: &mut Reader<R>,
23    parent_node: &mut Node,
24    is_root: bool,
25    buf: &mut Vec<u8>,
26) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
27where
28    R: Read + BufRead,
29{
30    loop {
31        let event = reader.read_event_into(buf)?;
32        match event {
33            Event::Start(e) => {
34                let name = String::from_utf8(e.name().as_ref().to_vec())?;
35                let mut attributes = HashMap::new();
36                for attr in e.attributes() {
37                    let attr = attr?;
38                    let key = String::from_utf8(attr.key.as_ref().to_vec())?;
39                    let value = String::from_utf8(attr.value.as_ref().to_vec())?;
40                    attributes.insert(key, value);
41                }
42                let mut child = Node {
43                    name: name,
44                    attributes: attributes,
45                    children: Vec::new(),
46                };
47                parse_children(reader, &mut child, false, buf)?;
48                parent_node.children.push(Child::Node(child));
49            }
50            Event::End(e) => {
51                let name = e.name();
52                if parent_node.name.as_bytes() == name.as_ref() {
53                    return Ok(());
54                } else {
55                    let name = String::from_utf8(name.as_ref().to_vec())?;
56                    return Err(format!(
57                        "End tag \"{}\" does not match start tag \"{}\"",
58                        name, parent_node.name
59                    )
60                    .into());
61                }
62            }
63            Event::Empty(e) => {
64                let name = String::from_utf8(e.name().as_ref().to_vec())?;
65                let mut attributes = HashMap::new();
66                for attr in e.attributes() {
67                    let attr = attr?;
68                    let key = String::from_utf8(attr.key.as_ref().to_vec())?;
69                    let value = String::from_utf8(attr.value.as_ref().to_vec())?;
70                    attributes.insert(key, value);
71                }
72                let child = Node {
73                    name: name,
74                    attributes: attributes,
75                    children: Vec::new(),
76                };
77                parent_node.children.push(Child::Node(child));
78            }
79            Event::Text(e) => {
80                let text = e.unescape()?;
81                let text = text.to_string();
82                parent_node.children.push(Child::Text(text));
83            }
84            Event::Eof => {
85                if is_root {
86                    return Ok(());
87                } else {
88                    return Err(format!("No end tag found for \"{}\"", parent_node.name).into());
89                }
90            }
91            _ => (),
92        }
93    }
94}
95
96pub fn parse_xml<R>(reader: R) -> Result<Vec<Child>, Box<dyn std::error::Error + Send + Sync>>
97where
98    R: Read + BufRead,
99{
100    let mut reader = Reader::from_reader(reader);
101    reader.config_mut().trim_text(true);
102    let mut root = Node {
103        name: String::from("root"),
104        attributes: HashMap::new(),
105        children: Vec::new(),
106    };
107    let mut buf = Vec::new();
108    parse_children(&mut reader, &mut root, true, &mut buf)?;
109    drop(buf);
110    return Ok(root.children);
111}