use crate::node::{ElementNode, Node};
pub fn search_element_by_attr<'a>(
node: &'a Node,
attributes_name: &str,
attributes_value: &str,
) -> Option<&'a ElementNode> {
if let Node::Element(element) = node {
for (attr_name, attr_value) in &element.attributes {
if attr_name == attributes_name && attributes_value == attr_value {
return Some(element);
}
}
for child in &element.children {
if let Some(found) = search_element_by_attr(child, attributes_name, attributes_value) {
return Some(found);
}
}
}
None
}
pub fn search_all_element_by_attr<'a>(
node: &'a Node,
attributes_name: &str,
attributes_value: &str,
) -> Vec<&'a ElementNode> {
let mut list_found = vec![];
if let Node::Element(element) = node {
for (attr_name, attr_value) in &element.attributes {
if attr_name == attributes_name && attributes_value == attr_value {
list_found.push(element);
}
}
for child in &element.children {
list_found.extend(search_element_by_attr(
child,
attributes_name,
attributes_value,
));
}
}
list_found
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_matching_id() {
let child_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![("id".to_string(), "child".to_string())],
children: vec![],
};
let parent_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![],
children: vec![Node::Element(child_node)],
};
let node = Node::Element(parent_node);
let result = search_element_by_attr(&node, "id", "child");
let result_all = search_all_element_by_attr(&node, "id", "child");
assert!(result.is_some());
assert_eq!(result.unwrap().tag_name, "div");
assert!(result_all.len() == 1);
}
#[test]
fn should_no_matching_id() {
let child_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![("id".to_string(), "child".to_string())],
children: vec![],
};
let parent_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![],
children: vec![Node::Element(child_node)],
};
let node = Node::Element(parent_node);
let result = search_element_by_attr(&node, "id", "dasfdsa");
let result_all = search_all_element_by_attr(&node, "id", "afdaf");
assert!(result.is_none());
assert!(result_all.len() == 0);
}
#[test]
fn should_grandchild_matching_id() {
let grandchild_node = ElementNode {
tag_name: "span".to_string(),
attributes: vec![("id".to_string(), "grandchild".to_string())],
children: vec![],
};
let child_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![("id".to_string(), "child".to_string())],
children: vec![Node::Element(grandchild_node)],
};
let parent_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![],
children: vec![Node::Element(child_node)],
};
let node = Node::Element(parent_node);
let result = search_element_by_attr(&node, "id", "grandchild");
assert!(result.is_some());
assert_eq!(result.unwrap().tag_name, "span");
}
#[test]
fn should_matching_class() {
let child_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![("class".to_string(), "child".to_string())],
children: vec![],
};
let parent_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![],
children: vec![Node::Element(child_node)],
};
let node = Node::Element(parent_node);
let result = search_element_by_attr(&node, "class", "child");
let result_all = search_all_element_by_attr(&node, "class", "child");
assert!(result.is_some());
assert!(result_all.len() == 1);
assert_eq!(result.unwrap().tag_name, "div");
}
#[test]
fn should_no_matching_class() {
let child_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![("class".to_string(), "child".to_string())],
children: vec![],
};
let parent_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![],
children: vec![Node::Element(child_node)],
};
let node = Node::Element(parent_node);
let result = search_element_by_attr(&node, "class", "dasfdsa");
let result_all = search_all_element_by_attr(&node, "class", "afdaf");
assert!(result.is_none());
assert!(result_all.len() == 0);
}
}