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
109
110
111
112
113
114
115
use error_chain::bail;
use std::collections::HashMap;
use log::debug;
use regex::{RegexBuilder};
use crate::errors::*;
use svg::node::element::tag::Type;
use svg::node::Value;
use svg::parser::Event;
use svg::Parser;
use crate::svg_tag::SVGTag;
pub fn parse_svg_string(input: &str) -> Result<SVGTag> {
let re = RegexBuilder::new(r"<svg.*</svg>").multi_line(true).dot_matches_new_line(true).build().unwrap();
if let Some(svg_string) = re.find(input) {
let mut p = svg::read(svg_string.as_str())?;
parse_svg_tag(&mut p)
} else {
bail!(format!("{} does not contain an svg", input))
}
}
pub fn parse_svg_tag(events: &mut Parser) -> Result<SVGTag> {
let first_node = events.next().ok_or(svg::parser::Error::new(
(0, 0),
"unable to parse tag, no new tag",
))?;
if let Event::Tag(name, tag_type, args) = first_node {
match tag_type {
Type::Start => Ok(rec_parse_svg_tag(name.to_string(), args, events)?),
Type::Empty => SVGTag::new(
name.to_string(),
"".to_string(),
Vec::new(),
args
),
Type::End => {
bail!(svg::parser::Error::new(
(0, 0),
"stream starts with end tag"
));
}
}
} else {
bail!(svg::parser::Error::new((0, 0), "not a tag in event stream"));
}
}
fn rec_parse_svg_tag(
name: String,
args: HashMap<String, Value>,
events: &mut Parser,
) -> Result<SVGTag> {
let mut children = Vec::new();
let mut text = "".to_string();
debug!("Starting tag type: {:?}", name);
while let Some(event) = events.next() {
match event {
Event::Error(e) => bail!(e),
Event::Tag(tag_name, tag_type, tag_args) => match tag_type {
svg::node::element::tag::Type::Start => {
children.push(rec_parse_svg_tag(tag_name.to_string(), tag_args, events)?)
},
svg::node::element::tag::Type::End => {
debug!("Ending tag type: {:?}", tag_name);
break;
},
svg::node::element::tag::Type::Empty => {
children.push(SVGTag::new_empty(tag_name.to_string(), tag_args)?);
debug!("Empty tag type: {:?}", tag_name);
}
},
Event::Text(t) => {
text = t.to_string();
}
Event::Comment => {}
Event::Declaration => panic!("1"),
Event::Instruction => panic!("!"),
}
}
Ok(SVGTag::new(name, text, children, args)?)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple() {
let data = r#"
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
Sorry, your browser does not support inline SVG.
</svg>
"#;
let mut parser = svg::read(data).unwrap();
let result = parse_svg_tag(&mut parser).unwrap();
assert_eq!(result.children.len(), 1);
assert_eq!(result.children[0].name, "circle");
assert_eq!(
result.text,
"Sorry, your browser does not support inline SVG."
);
}
}