reqwest_scraper/
jsonpath.rs1use crate::error::{Result, ScraperError};
4use jsonpath_lib as jsonpath;
5use serde::de::DeserializeOwned;
6
7#[derive(Debug)]
9pub struct Json {
10 value: serde_json::Value,
11}
12
13impl Json {
14 pub fn new(json: &str) -> Result<Self> {
16 let value = serde_json::from_str(json)?;
17 Ok(Self { value })
18 }
19
20 pub fn select<T: DeserializeOwned>(&self, path: &str) -> Result<Vec<T>> {
22 jsonpath::Selector::new()
23 .str_path(path)?
24 .value(&self.value)
25 .select_as()
26 .map_err(ScraperError::from)
27 }
28
29 pub fn select_one<T: DeserializeOwned>(&self, path: &str) -> Result<T> {
31 let result = jsonpath::Selector::new()
32 .str_path(path)?
33 .value(&self.value)
34 .select()?;
35 let v = result
36 .first()
37 .ok_or_else(|| {
38 ScraperError::JsonPathMatchError(format!(
39 "The \"{}\" jsonpath did not find data in json",
40 path
41 ))
42 })?
43 .to_owned();
44 Ok(serde_json::from_value::<T>(v.to_owned())?)
45 }
46
47 pub fn select_as_str(&self, path: &str) -> Result<String> {
49 jsonpath::Selector::new()
50 .str_path(path)?
51 .value(&self.value)
52 .select_as_str()
53 .map_err(ScraperError::from)
54 }
55
56 pub fn select_one_as_str(&self, path: &str) -> Result<String> {
58 let result = jsonpath::Selector::new()
59 .str_path(path)?
60 .value(&self.value)
61 .select()?;
62 let v = result
63 .first()
64 .ok_or_else(|| {
65 ScraperError::JsonPathMatchError(format!(
66 "The \"{}\" jsonpath did not find data in json",
67 path
68 ))
69 })?
70 .to_owned();
71 Ok(v.to_string())
72 }
73}
74
75#[cfg(test)]
76mod tests {
77
78 #[test]
79 #[allow(clippy::get_first)]
80 fn test_jsonpath() {
81 use super::Json;
82 use serde::Deserialize;
83 let json = r#"
84 {
85 "time":"2020.10.12 21:22:34",
86 "data":[
87 {"a":"A1","B":"b1","c":1},
88 {"a":"A2","B":"b2","c":2}
89 ]
90 }
91 "#;
92
93 let json = Json::new(json).unwrap();
94
95 assert_eq!(
96 json.select_one_as_str("$.time").unwrap(),
97 r#""2020.10.12 21:22:34""#
98 );
99
100 #[derive(Deserialize)]
101 struct DataItem {
102 a: String,
103 #[serde(rename = "B")]
104 b: String,
105 c: i32,
106 }
107
108 let data: Vec<DataItem> = json.select("$.data[*]").unwrap();
109 assert_eq!(data.len(), 2);
110
111 let d1 = data.get(0).unwrap();
112 assert_eq!(d1.a, "A1");
113 assert_eq!(d1.b, "b1");
114 assert_eq!(d1.c, 1);
115
116 let d2 = data.get(1).unwrap();
117 assert_eq!(d2.a, "A2");
118 assert_eq!(d2.b, "b2");
119 assert_eq!(d2.c, 2);
120 }
121}