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
mod error;
pub use error::*;
pub use xpather::{
self,
factory::ProduceIter,
value::Node,
Document,
Value
};
pub use scraper_macros::Scraper;
pub trait ScraperMain: Sized {
fn scrape(doc: &Document, container: Option<&Node>) -> Result<Self>;
}
pub fn evaluate<'a, S: Into<String>>(search: S, doc: &'a Document, container: Option<&'a Node>) -> Result<ProduceIter<'a>> {
Ok(if let Some(node) = container {
doc.evaluate_from(search, node)?
} else {
doc.evaluate(search)?
})
}
pub trait ConvertToValue<T>: Sized {
fn convert_from(self, doc: &Document) -> Result<T>;
}
impl<'a> ConvertToValue<Option<String>> for Result<ProduceIter<'a>> {
fn convert_from(self, _: &Document) -> Result<Option<String>> {
self?.next().map(value_to_string).transpose()
}
}
impl<'a> ConvertToValue<String> for Result<ProduceIter<'a>> {
fn convert_from(self, _: &Document) -> Result<String> {
self?.next()
.map(value_to_string)
.transpose()?
.ok_or(Error::ConvertFromValue(None))
}
}
impl<'a> ConvertToValue<Vec<String>> for Result<ProduceIter<'a>> {
fn convert_from(self, _: &Document) -> Result<Vec<String>> {
Ok(value_to_string_vec(self?).into_iter().filter_map(|v| v.ok()).collect())
}
}
impl<'a> ConvertToValue<Vec<Result<String>>> for Result<ProduceIter<'a>> {
fn convert_from(self, _: &Document) -> Result<Vec<Result<String>>> {
Ok(value_to_string_vec(self?))
}
}
impl<'a, T> ConvertToValue<Vec<T>> for Result<ProduceIter<'a>> where T: ScraperMain {
fn convert_from(self, doc: &Document) -> Result<Vec<T>> {
self?.map(|n| T::scrape(doc, Some(n?.as_node()?))).collect::<Result<Vec<_>>>()
}
}
impl<'a, T> ConvertToValue<Option<T>> for Result<ProduceIter<'a>> where T: ScraperMain {
fn convert_from(self, doc: &Document) -> Result<Option<T>> {
self?.next().map(|n| T::scrape(doc, Some(n?.as_node()?))).transpose()
}
}
pub fn value_to_string(value: xpather::Result<Value>) -> Result<String> {
match value? {
Value::Node(node) => {
value_to_string(node.value())
}
Value::String(v) => Ok(v),
value => Err(Error::ConvertFromValue(Some(value)))
}
}
pub fn value_to_string_vec(iter: ProduceIter) -> Vec<Result<String>> {
iter.map(value_to_string).collect()
}