1pub(crate) mod ontology;
4
5pub use ontology::Attribute;
6pub use ontology::Event;
7pub use ontology::Extension;
8pub use ontology::Log;
9pub use ontology::Trace;
10use quick_xml::events::BytesEnd;
11use quick_xml::events::BytesStart;
12use quick_xml::events::Event as XmlEvent;
13use std::collections::HashMap;
14use std::path::Path;
15
16const ATTRIBUTE_TAGS: [&str; 7] = [
17 "list", "string", "datetime", "long", "double", "boolean", "id",
18];
19
20fn parse_attribute(attributee: &roxmltree::Node) -> (String, Attribute) {
21 let key = attributee.attribute("key").unwrap().to_owned();
22 match attributee.attribute("value") {
23 Some(value) => {
24 let value = value.to_owned();
25 let value = match attributee.tag_name().name() {
26 "string" => Attribute::String(value),
27 "datetime" => Attribute::DateTime(value),
28 "long" => Attribute::Long(value.parse().unwrap()),
29 "double" => Attribute::Double(value.parse().unwrap()),
30 "boolean" => Attribute::Boolean(value.parse().unwrap()),
31 "id" => Attribute::ID(value),
32 _ => panic!(),
33 };
34 (key, value)
35 }
36 None => {
37 let mut sub_attributes = HashMap::new();
38 for sub_attributee in attributee
39 .children()
40 .filter(|e| ATTRIBUTE_TAGS.contains(&e.tag_name().name()))
41 {
42 let (k, v) = parse_attribute(&sub_attributee);
43 sub_attributes.insert(k, v);
44 }
45 let value = Attribute::List(sub_attributes);
46 (key, value)
47 }
48 }
49}
50
51fn parse_event(evente: &roxmltree::Node) -> Event {
52 let mut attributes = HashMap::new();
53 for attributee in evente
54 .children()
55 .filter(|e| ATTRIBUTE_TAGS.contains(&e.tag_name().name()))
56 {
57 let (key, value) = parse_attribute(&attributee);
58 attributes.insert(key, value);
59 }
60 Event { attributes }
61}
62
63fn parse_trace(tracee: &roxmltree::Node) -> Trace {
64 let mut attributes = HashMap::new();
65 for attributee in tracee
66 .children()
67 .filter(|e| ATTRIBUTE_TAGS.contains(&e.tag_name().name()))
68 {
69 let (key, value) = parse_attribute(&attributee);
70 attributes.insert(key, value);
71 }
72 let mut events = Vec::new();
73 for evente in tracee.children().filter(|e| e.tag_name().name() == "event") {
74 events.push(parse_event(&evente));
75 }
76 Trace { attributes, events }
77}
78
79fn parse_log(loge: &roxmltree::Node) -> Log {
80 let version = loge.attribute("version").unwrap().parse().unwrap();
81 let features = loge
82 .attribute("features")
83 .unwrap()
84 .split(',')
85 .map(|s| s.trim())
86 .map(String::from)
87 .collect();
88 let mut log = Log::new(version, features);
89 for exte in loge
90 .children()
91 .filter(|e| e.tag_name().name() == "extension")
92 {
93 let name = exte.attribute("name").unwrap().to_owned();
94 let prefix = exte.attribute("prefix").unwrap().to_owned();
95 let uri = exte.attribute("uri").unwrap().to_owned();
96 log.extensions.push(Extension { name, prefix, uri });
97 }
98 for attributee in loge
99 .children()
100 .filter(|e| ATTRIBUTE_TAGS.contains(&e.tag_name().name()))
101 {
102 let (key, value) = parse_attribute(&attributee);
103 log.attributes.insert(key, value);
104 }
105 for tracee in loge.children().filter(|e| e.tag_name().name() == "trace") {
106 log.traces.push(parse_trace(&tracee));
107 }
108 for evente in loge.children().filter(|e| e.tag_name().name() == "event") {
109 log.events.push(parse_event(&evente));
110 }
111 log
112}
113
114pub fn read<P: AsRef<Path>>(path: P) -> Vec<Log> {
116 let text = std::fs::read_to_string(path).unwrap();
117 let document = roxmltree::Document::parse(&text).unwrap();
118 let mut logs = Vec::new();
119 for log in document
120 .root()
121 .children()
122 .filter(|e| e.tag_name().name() == "log")
123 {
124 logs.push(parse_log(&log));
125 }
126 logs
127}
128
129fn write_extension(extension: &Extension, events: &mut Vec<XmlEvent>) {
130 let mut exte = BytesStart::new("extension");
131 exte.push_attribute(("name", extension.name.as_str()));
132 exte.push_attribute(("prefix", extension.prefix.as_str()));
133 exte.push_attribute(("uri", extension.uri.as_str()));
134 events.push(XmlEvent::Start(exte));
135 events.push(XmlEvent::End(BytesEnd::new("extension")));
136}
137
138fn write_attribute(attribute: (&String, &Attribute), events: &mut Vec<XmlEvent>) {
139 let (k, v) = attribute;
140 let element_name = match v {
141 Attribute::List(_) => "list",
142 Attribute::String(_) => "string",
143 Attribute::Long(_) => "long",
144 Attribute::Double(_) => "double",
145 Attribute::DateTime(_) => "date",
146 Attribute::Boolean(_) => "boolean",
147 Attribute::ID(_) => "id",
148 };
149 let mut attribute = BytesStart::new(element_name);
150 attribute.push_attribute(("key", k.as_str()));
151 match v {
152 Attribute::List(list) => {
153 events.push(XmlEvent::Start(BytesStart::new("list")));
154 for sub_attribute in list {
155 write_attribute(sub_attribute, events);
156 }
157 events.push(XmlEvent::End(BytesEnd::new("list")));
158 }
159 Attribute::String(value) => {
160 attribute.push_attribute(("value", value.as_str()));
161 }
162 Attribute::Long(value) => {
163 attribute.push_attribute(("value", value.to_string().as_str()));
164 }
165 Attribute::Double(value) => {
166 attribute.push_attribute(("value", value.to_string().as_str()));
167 }
168 Attribute::DateTime(value) => {
169 attribute.push_attribute(("value", value.to_string().as_str()));
170 }
171 Attribute::Boolean(value) => {
172 attribute.push_attribute(("value", value.to_string().as_str()));
173 }
174 Attribute::ID(value) => {
175 attribute.push_attribute(("value", value.to_string().as_str()));
176 }
177 }
178 events.push(XmlEvent::Start(attribute));
179 events.push(XmlEvent::End(BytesEnd::new(element_name)));
180}
181
182fn write_event(event: &Event, events: &mut Vec<XmlEvent>) {
183 events.push(XmlEvent::Start(BytesStart::new("event")));
184 for attribute in &event.attributes {
185 write_attribute(attribute, events);
186 }
187 events.push(XmlEvent::End(BytesEnd::new("event")));
188}
189
190fn write_trace(trace: &Trace, events: &mut Vec<XmlEvent>) {
191 events.push(XmlEvent::Start(BytesStart::new("trace")));
192 for attribute in &trace.attributes {
193 write_attribute(attribute, events);
194 }
195 for event in &trace.events {
196 write_event(event, events);
197 }
198 events.push(XmlEvent::End(BytesEnd::new("trace")));
199}
200
201fn write_log(log: &Log, events: &mut Vec<XmlEvent>) {
202 let mut loge = BytesStart::new("log");
203 loge.push_attribute(("version", log.version.as_str()));
204 loge.push_attribute(("features", log.features.join(",").as_str()));
205 events.push(XmlEvent::Start(loge));
206 for extension in &log.extensions {
207 write_extension(extension, events);
208 }
209 for attribute in &log.attributes {
210 write_attribute(attribute, events);
211 }
212 for trace in &log.traces {
213 write_trace(trace, events);
214 }
215 for event in &log.events {
216 write_event(event, events);
217 }
218 events.push(XmlEvent::End(BytesEnd::new("log")));
219}
220
221pub fn write<P: AsRef<Path>>(log: &Log, path: P) {
223 use quick_xml::Writer;
224 use std::io::Cursor;
225 let mut events = Vec::new();
226 write_log(log, &mut events);
227 let mut writer = Writer::new(Cursor::new(Vec::new()));
228 for event in events {
229 writer.write_event(event).unwrap();
230 }
231 let contents = writer.into_inner().into_inner();
232 std::fs::write(path, contents).unwrap();
233}