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
use std::io::Read;
use error_chain::{bail, ensure};
use xml::reader::XmlEvent;
use crate::errors::*;
use crate::parser::{verify_starting_tag, Context};
pub fn consume<R: Read>(
context: &mut Context<R>,
tagname: &'static str,
allow_empty: bool,
) -> Result<String> {
verify_starting_tag(context, tagname)?;
let mut string = String::new();
for event in context.reader() {
match event.chain_err(|| "error while parsing XML")? {
XmlEvent::StartElement { ref name, .. } => {
bail!(ErrorKind::InvalidChildElement(
name.local_name.clone(),
tagname
));
}
XmlEvent::Characters(content) => string = content,
XmlEvent::EndElement { ref name } => {
ensure!(
name.local_name == tagname,
ErrorKind::InvalidClosingTag(name.local_name.clone(), tagname)
);
if allow_empty || !string.is_empty() {
return Ok(string);
}
bail!("no content inside string");
}
_ => {}
}
}
bail!(ErrorKind::MissingClosingTag(tagname));
}
#[cfg(test)]
mod tests {
use super::consume;
use crate::GpxVersion;
#[test]
fn consume_simple_string() {
let result = consume!(
"<string>hello world</string>",
GpxVersion::Gpx11,
"string",
false
);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "hello world");
}
#[test]
fn consume_new_tag() {
let result = consume!("<foo>bar<baz></baz></foo>", GpxVersion::Gpx11, "foo", false);
assert!(result.is_err());
}
#[test]
fn consume_start_tag() {
let result = consume!("bar</foo>", GpxVersion::Gpx11, "foo", false);
assert!(result.is_err());
}
#[test]
fn consume_end_tag() {
let result = consume!("<foo>bar", GpxVersion::Gpx11, "foo", false);
assert!(result.is_err());
}
#[test]
fn consume_no_body() {
let result = consume!("<foo></foo>", GpxVersion::Gpx11, "foo", false);
assert!(result.is_err());
}
#[test]
fn consume_different_ending_tag() {
let result = consume!("<foo></foobar>", GpxVersion::Gpx11, "foo", false);
assert!(result.is_err());
}
}