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
use std::fmt::Display;
use std::io::BufRead;
use std::path::Path;
use std::str::FromStr;
use crate::utils::ResultLogExt;
use minidom::{Children, Element};
use quick_xml::Reader;
use failure::{format_err, Error};
pub fn attr_map<'a, T>(from: &'a Element, name: &str, elemname: &'static str) -> Result<T, Error>
where
T: From<&'a str>,
{
from.attr(name)
.map(T::from)
.ok_or_else(|| format_err!("{} not found in {} element", name, elemname))
}
pub fn attr_parse_hex<'a>(
from: &'a Element,
name: &str,
elemname: &'static str,
) -> Result<u64, Error> {
from.attr(name)
.ok_or_else(|| format_err!("{} not found in {} element", name, elemname))
.and_then(|st| {
if st.starts_with("0x") {
u64::from_str_radix(&st[2..], 16).map_err(|e| format_err!("{}", e))
} else if st.starts_with('0') {
u64::from_str_radix(&st[1..], 8).map_err(|e| format_err!("{}", e))
} else {
u64::from_str_radix(st, 10).map_err(|e| format_err!("{}", e))
}
})
}
pub fn attr_parse<'a, T, E>(
from: &'a Element,
name: &str,
elemname: &'static str,
) -> Result<T, Error>
where
T: FromStr<Err = E>,
E: Display,
{
from.attr(name)
.ok_or_else(|| format_err!("{} not found in {} element", name, elemname))
.and_then(|st| st.parse::<T>().map_err(|e| format_err!("{}", e)))
}
pub fn child_text<'a>(
from: &'a Element,
name: &str,
elemname: &'static str,
) -> Result<String, Error> {
match get_child_no_ns(from, name) {
Some(child) => Ok(child.text()),
None => Err(format_err!(
"child element \"{}\" not found in \"{}\" element",
name,
elemname
)),
}
}
pub fn get_child_no_ns<'a>(from: &'a Element, name: &str) -> Option<&'a Element> {
for child in from.children() {
if child.name() == name {
return Some(child);
}
}
None
}
pub fn assert_root_name(from: &Element, name: &str) -> Result<(), Error> {
if from.name() != name {
Err(format_err!(
"tried to parse element \"{}\" from element \"{}\"",
name,
from.name()
))
} else {
Ok(())
}
}
pub trait FromElem: Sized {
fn from_elem(e: &Element) -> Result<Self, Error>;
fn from_reader<T: BufRead>(r: &mut Reader<T>) -> Result<Self, Error> {
let mut root = Element::from_reader(r)?;
root.set_attr::<&str, Option<String>>("xmlns:xs", None);
Self::from_elem(&root)
}
fn from_string(s: &str) -> Result<Self, Error> {
let mut r = Reader::from_str(s);
Self::from_reader(&mut r)
}
fn from_path(p: &Path) -> Result<Self, Error> {
let mut r = Reader::from_file(p)?;
Self::from_reader(&mut r)
}
fn vec_from_children(clds: Children) -> Vec<Self> {
clds.flat_map(move |cld| Self::from_elem(cld).ok_warn().into_iter())
.collect()
}
}