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
use crate::pipeline::{ScrapeContext, ScrapeError}; use json_dotpath::DotPaths; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter, Result as FormatResult}; pub type JsonValue = serde_json::Value; #[derive(Serialize, Deserialize, Debug, Clone)] pub enum Value { Constant(String), Context(String), ElementText, ElementAttribute(String), } impl Display for Value { fn fmt(&self, fmt: &mut Formatter<'_>) -> FormatResult { write!(fmt, "{:?}", self) } } impl Value { pub fn constant<T: Into<String>>(value: T) -> Self { Value::Constant(value.into()) } pub fn context<T: Into<String>>(key: T) -> Self { Value::Context(key.into()) } pub fn element_attribute<T: Into<String>>(attribute: T) -> Self { Value::ElementAttribute(attribute.into()) } pub async fn resolve(&self, context: &mut ScrapeContext) -> Result<Option<String>, ScrapeError> { match self { Value::Constant(value) => Ok(Some(value.to_owned())), Value::Context(key) => context .values .dot_get::<JsonValue>(&key) .map(to_string) .map_err(|_| ScrapeError::ValueResolveError), Value::ElementText => { let element = context.current_element.as_mut().ok_or(ScrapeError::MissingElement)?; element .text() .await .map(Option::Some) .map_err(ScrapeError::WebdriverCommandError) } Value::ElementAttribute(attribute) => { let element = context.current_element.as_mut().ok_or(ScrapeError::MissingElement)?; element .attr(attribute) .await .map_err(ScrapeError::WebdriverCommandError) } } } } fn to_string(value: Option<JsonValue>) -> Option<String> { value.map(|value| match value { JsonValue::String(value) => value.clone(), value => value.to_string(), }) }