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}