node-html-parser 0.1.1

Fast HTML parser for Rust & WASM producing a lightweight DOM with CSS selector querying.
Documentation
use crate::css_select::types::{Adapter, AttributeAction, AttributeSelector};

pub fn compose_attribute<'a, A: Adapter + 'a>(
	next: Box<dyn Fn(&A::HTMLElement) -> bool + 'a>,
	sel: &AttributeSelector,
	adapter: &'a A,
) -> Box<dyn Fn(&A::HTMLElement) -> bool + 'a> {
	let name = sel.name.clone();
	let action = sel.action.clone();
	let value = sel.value.clone();
	let ignore_case = sel.ignore_case;
	Box::new(move |el| {
		let attr = adapter.get_attribute(el, &name);
		match action {
			AttributeAction::Exists => {
				if attr.is_some() {
					return next(el);
				} else {
					return false;
				}
			}
			AttributeAction::Equals => {
				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
					let (a, b) = if ignore_case {
						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
					} else {
						(v.to_string(), val.to_string())
					};
					if a == b {
						return next(el);
					}
				}
				false
			}
			AttributeAction::Not => {
				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
					let (a, b) = if ignore_case {
						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
					} else {
						(v.to_string(), val.to_string())
					};
					if a == b {
						return false;
					}
				}
				next(el)
			}
			AttributeAction::Start => {
				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
					let (a, b) = if ignore_case {
						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
					} else {
						(v.to_string(), val.to_string())
					};
					if a.starts_with(&b) {
						return next(el);
					}
				}
				false
			}
			AttributeAction::End => {
				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
					let (a, b) = if ignore_case {
						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
					} else {
						(v.to_string(), val.to_string())
					};
					if a.ends_with(&b) {
						return next(el);
					}
				}
				false
			}
			AttributeAction::Any => {
				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
					let (a, b) = if ignore_case {
						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
					} else {
						(v.to_string(), val.to_string())
					};
					if a.contains(&b) {
						return next(el);
					}
				}
				false
			}
			AttributeAction::Hyphen => {
				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
					let (a, b) = if ignore_case {
						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
					} else {
						(v.to_string(), val.to_string())
					};
					if a == b || a.starts_with(&format!("{}-", b)) {
						return next(el);
					}
				}
				false
			}
			AttributeAction::Element => {
				if let (Some(v), Some(val)) = (attr, value.as_ref()) {
					let (a, b) = if ignore_case {
						(v.to_ascii_lowercase(), val.to_ascii_lowercase())
					} else {
						(v.to_string(), val.to_string())
					};
					if a.split_whitespace().any(|t| t == b) {
						return next(el);
					}
				}
				false
			}
		}
	})
}