node_html_parser/css_select/
attributes.rs

1use crate::css_select::types::{Adapter, AttributeAction, AttributeSelector};
2
3pub fn compose_attribute<'a, A: Adapter + 'a>(
4	next: Box<dyn Fn(&A::HTMLElement) -> bool + 'a>,
5	sel: &AttributeSelector,
6	adapter: &'a A,
7) -> Box<dyn Fn(&A::HTMLElement) -> bool + 'a> {
8	let name = sel.name.clone();
9	let action = sel.action.clone();
10	let value = sel.value.clone();
11	let ignore_case = sel.ignore_case;
12	Box::new(move |el| {
13		let attr = adapter.get_attribute(el, &name);
14		match action {
15			AttributeAction::Exists => {
16				if attr.is_some() {
17					return next(el);
18				} else {
19					return false;
20				}
21			}
22			AttributeAction::Equals => {
23				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
24					let (a, b) = if ignore_case {
25						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
26					} else {
27						(v.to_string(), val.to_string())
28					};
29					if a == b {
30						return next(el);
31					}
32				}
33				false
34			}
35			AttributeAction::Not => {
36				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
37					let (a, b) = if ignore_case {
38						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
39					} else {
40						(v.to_string(), val.to_string())
41					};
42					if a == b {
43						return false;
44					}
45				}
46				next(el)
47			}
48			AttributeAction::Start => {
49				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
50					let (a, b) = if ignore_case {
51						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
52					} else {
53						(v.to_string(), val.to_string())
54					};
55					if a.starts_with(&b) {
56						return next(el);
57					}
58				}
59				false
60			}
61			AttributeAction::End => {
62				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
63					let (a, b) = if ignore_case {
64						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
65					} else {
66						(v.to_string(), val.to_string())
67					};
68					if a.ends_with(&b) {
69						return next(el);
70					}
71				}
72				false
73			}
74			AttributeAction::Any => {
75				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
76					let (a, b) = if ignore_case {
77						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
78					} else {
79						(v.to_string(), val.to_string())
80					};
81					if a.contains(&b) {
82						return next(el);
83					}
84				}
85				false
86			}
87			AttributeAction::Hyphen => {
88				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
89					let (a, b) = if ignore_case {
90						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
91					} else {
92						(v.to_string(), val.to_string())
93					};
94					if a == b || a.starts_with(&format!("{}-", b)) {
95						return next(el);
96					}
97				}
98				false
99			}
100			AttributeAction::Element => {
101				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
102					let (a, b) = if ignore_case {
103						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
104					} else {
105						(v.to_string(), val.to_string())
106					};
107					if a.split_whitespace().any(|t| t == b) {
108						return next(el);
109					}
110				}
111				false
112			}
113		}
114	})
115}