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
mod error;

pub use error::*;

pub use xpather::{
	self,
	Document,
	Node,
	Value
};


pub trait ScraperMain: Sized {
	fn scrape(doc: &Document, container: Option<Node>) -> Result<Self>;
}

pub fn evaluate<S: Into<String>>(search: S, doc: &Document, container: Option<Node>) -> Option<Value> {
	if let Some(node) = container {
		doc.evaluate_from(search, node)
	} else {
		doc.evaluate(search)
	}
}

pub trait ConvertFromValue<T>: Sized {
	fn convert_from(self, doc: &Document) -> Result<T>;
}

impl ConvertFromValue<Option<String>> for Option<Value> {
	fn convert_from(self, _: &Document) -> Result<Option<String>> {
		Ok(if let Some(value) = self {
			value_to_string(&value)
		} else {
			None
		})
	}
}

impl ConvertFromValue<String> for Option<Value> {
	fn convert_from(self, _: &Document) -> Result<String> {
		Ok(if let Some(value) = self {
			value_to_string(&value).ok_or(Error::ConvertFromValue(Some(value)))?
		} else {
			return Err(Error::ConvertFromValue(None));
		})
	}
}

impl ConvertFromValue<Vec<String>> for Option<Value> {
	fn convert_from(self, _: &Document) -> Result<Vec<String>> {
		Ok(if let Some(value) = self {
			value_to_string_vec(value)
		} else {
			Vec::new()
		})
	}
}

impl<T> ConvertFromValue<Vec<T>> for Option<Value> where T: ScraperMain {
	fn convert_from(self, doc: &Document) -> Result<Vec<T>> {
		Ok(if let Some(value) = self.map(|v| v.into_iterset()).transpose()? {
			value.map(|n| T::scrape(doc, Some(n))).collect::<Result<Vec<_>>>()?
		} else {
			Vec::new()
		})
	}
}


pub fn value_to_string(value: &Value) -> Option<String> {
	match value {
		Value::Nodeset(set) => {
			set.nodes.first()
			.and_then(|n| value_to_string(&n.value()))
		}

		Value::String(v) => Some(v.clone()),

		_ => None
	}
}

pub fn value_to_string_vec(value: Value) -> Vec<String> {
	match value {
		Value::Nodeset(set) => {
			set.nodes.into_iter().filter_map(|n| value_to_string(&n.value())).collect()
		}

		Value::String(v) => vec![v],

		_ => Vec::new()
	}
}