1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use quick_xml::events::Event;
use quick_xml::Reader;
use std::fs::File;
use std::io::BufReader;
pub mod structs;
use mathml_macros::*;
pub use structs::*;
pub fn parse_fragment(
mut reader: Reader<BufReader<File>>,
) -> (Vec<MathNode>, Reader<BufReader<File>>) {
reader.trim_text(true);
reader.expand_empty_elements(true);
let mut buf = Vec::new();
let mut stack: Vec<NodeIndex> = Vec::new();
let mut container = Vec::new();
let mut container_len = 0;
container.push(MathNode::default());
container_len += 1;
let mut current = 0;
stack.push(current);
loop {
match reader.read_event(&mut buf) {
Ok(Event::Start(ref e)) => {
let mut new_tag = None;
match e.name() {
b"apply" => attach![Apply to Root | Apply],
b"times" => attach![Op::Times to Apply],
b"power" => attach![Op::Power to Apply],
b"ci" => attach![Ci to Apply],
b"cn" => attach![Cn with
r#type as String,
to Apply],
_ => {
panic!("Tag not parsed: {}", std::str::from_utf8(e.name()).unwrap());
}
}
match new_tag {
Some(t) => {
container.push(t);
container_len += 1;
}
None => {}
}
}
Ok(Event::End(ref e)) => match e.name() {
b"apply" => close![Apply],
b"times" => close![Op],
b"power" => close![Op],
b"ci" => close![Ci],
b"cn" => close![Cn],
b"math" => break,
_ => {}
},
Ok(Event::Text(e)) => {
let s = e.unescape_and_decode(&reader).unwrap();
match container[current] {
MathNode::Ci(..) => {
container[current] = MathNode::Ci(Ci::with_text(s));
}
MathNode::Cn(ref mut cn) => match cn.r#type.as_deref() {
Some("integer") => {
cn.integer = Some(s.parse::<i32>().expect("Incorrect type"))
}
_ => {
panic!("Math type did not match for cn: {:?}", cn);
}
},
_ => {
panic!("Text not parsed in {:?}: {}", container[current], s);
}
}
}
Ok(Event::Eof) => break,
Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
_ => (),
}
}
(container, reader)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let filename = "../../testsuites/core-semantic/00004/00004-sbml-l3v2.xml";
let reader = Reader::from_file(filename).expect("File error.");
parse_fragment(reader);
}
}