parse_html/dom/
dom_tree.rs1use crate::{
2 lexer::lexer_trait::LexerTrait,
3 node::{ElementNode, Node},
4 parser::{error::ParserError, parser_trait::ParserTrait},
5};
6
7use super::{
8 search_by_attr::{search_all_element_by_attr, search_element_by_attr},
9 search_by_tag_name::{search_all_element_by_tag_name, search_element_by_tag_name},
10};
11
12pub struct DomTree {
13 pub nodes: Vec<Node>,
14}
15
16impl DomTree {
17 pub fn new<L, P>(html: &str) -> Result<Self, ParserError>
18 where
19 L: LexerTrait,
20 P: ParserTrait,
21 {
22 let mut lexer = L::new(html);
23 let tokens = lexer.tokenize();
24
25 let mut parser = P::new(tokens);
26 let nodes = parser.parse()?;
27
28 Ok(Self { nodes })
29 }
30
31 pub fn get_by_id(&self, id_value: &str) -> Option<&ElementNode> {
32 for node in &self.nodes {
33 if let Some(found) = search_element_by_attr(node, "id", id_value) {
34 return Some(found);
35 }
36 }
37 None
38 }
39
40 pub fn get_all_by_id(&self, id_value: &str) -> Vec<&ElementNode> {
41 let mut list_found = vec![];
42 for node in &self.nodes {
43 list_found.extend(search_all_element_by_attr(node, "id", id_value));
44 }
45 list_found
46 }
47
48 pub fn get_by_class(&self, value: &str) -> Option<&ElementNode> {
49 for node in &self.nodes {
50 if let Some(found) = search_element_by_attr(node, "class", value) {
51 return Some(found);
52 }
53 }
54 None
55 }
56
57 pub fn get_all_by_class(&self, value: &str) -> Vec<&ElementNode> {
58 let mut list_found = vec![];
59 for node in &self.nodes {
60 list_found.extend(search_all_element_by_attr(node, "class", value));
61 }
62 list_found
63 }
64
65 pub fn get_by_tag_name(&self, tag_name: &str) -> Option<&ElementNode> {
66 for node in &self.nodes {
67 if let Some(found) = search_element_by_tag_name(node, tag_name) {
68 return Some(found);
69 }
70 }
71 None
72 }
73
74 pub fn get_all_by_tag_name(&self, tag_name: &str) -> Vec<&ElementNode> {
75 let mut list_found = vec![];
76 for node in &self.nodes {
77 list_found.extend(search_all_element_by_tag_name(node, tag_name));
78 }
79 list_found
80 }
81
82 pub fn get_by_attr(
83 &self,
84 attributes_name: &str,
85 attributes_value: &str,
86 ) -> Option<&ElementNode> {
87 for node in &self.nodes {
88 if let Some(found) = search_element_by_attr(node, attributes_name, attributes_value) {
89 return Some(found);
90 }
91 }
92 None
93 }
94
95 pub fn get_all_by_attr(
96 &self,
97 attributes_name: &str,
98 attributes_value: &str,
99 ) -> Vec<&ElementNode> {
100 let mut list_found = vec![];
101 for node in &self.nodes {
102 list_found.extend(search_all_element_by_attr(
103 node,
104 attributes_name,
105 attributes_value,
106 ));
107 }
108 list_found
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_chainning() {
118 let grandchild_node = ElementNode {
119 tag_name: "div".to_string(),
120 attributes: vec![("id".to_string(), "grandchild_node".to_string())],
121 children: vec![],
122 };
123
124 let child_node = ElementNode {
125 tag_name: "div".to_string(),
126 attributes: vec![
127 ("id".to_string(), "child".to_string()),
128 ("class".to_string(), "space".to_string()),
129 ],
130 children: vec![Node::Element(grandchild_node)],
131 };
132
133 let button = ElementNode {
134 tag_name: "button".to_string(),
135 attributes: vec![("class".to_string(), "btn".to_string())],
136 children: vec![Node::Text("envoyer".to_string())],
137 };
138
139 let parent_node = ElementNode {
140 tag_name: "div".to_string(),
141 attributes: vec![("class".to_string(), "mt-1".to_string())],
142 children: vec![Node::Element(child_node), Node::Element(button)],
143 };
144
145 let container = ElementNode {
146 tag_name: "div".to_string(),
147 attributes: vec![("class".to_string(), "container".to_string())],
148 children: vec![Node::Element(parent_node)],
149 };
150
151 let found_parent = container.get_by_class("mt-1");
152 let parent_element = found_parent.unwrap();
153 let found_child = parent_element.get_by_class("space");
154 let child_element = found_child.unwrap();
155 let found_grandchild = child_element.get_by_id("grandchild_node");
156 let found_child_not_exist = child_element.get_by_id("adfaf");
157 let found_button = container.get_by_tag_name("button");
158 let result_all_div_from_container = container.get_all_by_tag_name("div");
159 let result_all_button = container.get_all_by_tag_name("button");
160 let result_all_span = container.get_all_by_tag_name("span");
161
162 assert!(found_grandchild.is_some());
163 assert!(found_child_not_exist.is_none());
164 assert!(found_button.is_some());
165 assert!(result_all_div_from_container.len() == 3);
166 assert!(result_all_button.len() == 1);
167 assert!(result_all_span.len() == 0);
168 }
169}