parse_html/dom/
search.rs

1use crate::node::{ElementNode, Node};
2
3pub fn search_node_attr<'a>(
4    node: &'a Node,
5    attributes_name: &str,
6    attributes_value: &str,
7) -> Option<&'a ElementNode> {
8    if let Node::Element(element) = node {
9        for (attr_name, attr_value) in &element.attributes {
10            if attr_name == attributes_name && attributes_value == attr_value {
11                return Some(element);
12            }
13        }
14        for child in &element.children {
15            if let Some(found) = search_node_attr(child, attributes_name, attributes_value) {
16                return Some(found);
17            }
18        }
19    }
20    None
21}
22
23#[cfg(test)]
24mod tests {
25    use super::*;
26
27    #[test]
28    fn should_matching_id() {
29        let child_node = ElementNode {
30            tag_name: "div".to_string(),
31            attributes: vec![("id".to_string(), "child".to_string())],
32            children: vec![],
33        };
34
35        let parent_node = ElementNode {
36            tag_name: "div".to_string(),
37            attributes: vec![],
38            children: vec![Node::Element(child_node)],
39        };
40
41        let node = Node::Element(parent_node);
42        let result = search_node_attr(&node, "id", "child");
43        assert!(result.is_some());
44        assert_eq!(result.unwrap().tag_name, "div");
45    }
46
47    #[test]
48    fn should_no_matching_id() {
49        let child_node = ElementNode {
50            tag_name: "div".to_string(),
51            attributes: vec![("id".to_string(), "child".to_string())],
52            children: vec![],
53        };
54
55        let parent_node = ElementNode {
56            tag_name: "div".to_string(),
57            attributes: vec![],
58            children: vec![Node::Element(child_node)],
59        };
60
61        let node = Node::Element(parent_node);
62        let result = search_node_attr(&node, "id", "dasfdsa");
63        assert!(result.is_none());
64    }
65
66    #[test]
67    fn should_grandchild_matching_id() {
68        let grandchild_node = ElementNode {
69            tag_name: "span".to_string(),
70            attributes: vec![("id".to_string(), "grandchild".to_string())],
71            children: vec![],
72        };
73
74        let child_node = ElementNode {
75            tag_name: "div".to_string(),
76            attributes: vec![("id".to_string(), "child".to_string())],
77            children: vec![Node::Element(grandchild_node)],
78        };
79
80        let parent_node = ElementNode {
81            tag_name: "div".to_string(),
82            attributes: vec![],
83            children: vec![Node::Element(child_node)],
84        };
85
86        let node = Node::Element(parent_node);
87        let result = search_node_attr(&node, "id", "grandchild");
88        assert!(result.is_some());
89        assert_eq!(result.unwrap().tag_name, "span");
90    }
91
92    #[test]
93    fn should_matching_class() {
94        let child_node = ElementNode {
95            tag_name: "div".to_string(),
96            attributes: vec![("class".to_string(), "child".to_string())],
97            children: vec![],
98        };
99
100        let parent_node = ElementNode {
101            tag_name: "div".to_string(),
102            attributes: vec![],
103            children: vec![Node::Element(child_node)],
104        };
105
106        let node = Node::Element(parent_node);
107        let result = search_node_attr(&node, "class", "child");
108        assert!(result.is_some());
109        assert_eq!(result.unwrap().tag_name, "div");
110    }
111
112    #[test]
113    fn should_no_matching_class() {
114        let child_node = ElementNode {
115            tag_name: "div".to_string(),
116            attributes: vec![("class".to_string(), "child".to_string())],
117            children: vec![],
118        };
119
120        let parent_node = ElementNode {
121            tag_name: "div".to_string(),
122            attributes: vec![],
123            children: vec![Node::Element(child_node)],
124        };
125
126        let node = Node::Element(parent_node);
127        let result = search_node_attr(&node, "class", "dasfdsa");
128        assert!(result.is_none());
129    }
130}