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::{search_by_attr::search_node_attr, search_by_tag_name::search_node_by_tag_name};
8
9pub struct DomTree {
10 pub nodes: Vec<Node>,
11}
12
13impl DomTree {
14 pub fn new<L, P>(html: &str) -> Result<Self, ParserError>
15 where
16 L: LexerTrait,
17 P: ParserTrait,
18 {
19 let mut lexer = L::new(html);
20 let tokens = lexer.tokenize();
21
22 let mut parser = P::new(tokens);
23 let nodes = parser.parse()?;
24
25 Ok(Self { nodes })
26 }
27
28 pub fn get_by_id(&self, id_value: &str) -> Option<&ElementNode> {
29 for node in &self.nodes {
30 if let Some(found) = search_node_attr(node, "id", id_value) {
31 return Some(found);
32 }
33 }
34 None
35 }
36
37 pub fn get_by_class(&self, value: &str) -> Option<&ElementNode> {
38 for node in &self.nodes {
39 if let Some(found) = search_node_attr(node, "class", value) {
40 return Some(found);
41 }
42 }
43 None
44 }
45
46 pub fn get_by_tag_name(&self, tag_name: &str) -> Option<&ElementNode> {
47 for node in &self.nodes {
48 if let Some(found) = search_node_by_tag_name(node, tag_name) {
49 return Some(found);
50 }
51 }
52 None
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn test_chainning() {
62 let grandchild_node = ElementNode {
63 tag_name: "div".to_string(),
64 attributes: vec![("id".to_string(), "grandchild_node".to_string())],
65 children: vec![],
66 };
67
68 let child_node = ElementNode {
69 tag_name: "div".to_string(),
70 attributes: vec![
71 ("id".to_string(), "child".to_string()),
72 ("class".to_string(), "space".to_string()),
73 ],
74 children: vec![Node::Element(grandchild_node)],
75 };
76
77 let button = ElementNode {
78 tag_name: "button".to_string(),
79 attributes: vec![("class".to_string(), "btn".to_string())],
80 children: vec![Node::Text("envoyer".to_string())],
81 };
82
83 let parent_node = ElementNode {
84 tag_name: "div".to_string(),
85 attributes: vec![("class".to_string(), "mt-1".to_string())],
86 children: vec![Node::Element(child_node), Node::Element(button)],
87 };
88
89 let container = ElementNode {
90 tag_name: "div".to_string(),
91 attributes: vec![("class".to_string(), "container".to_string())],
92 children: vec![Node::Element(parent_node)],
93 };
94
95 let found_parent = container.get_by_class("mt-1");
96 let parent_element = found_parent.unwrap();
97 let found_child = parent_element.get_by_class("space");
98 let child_element = found_child.unwrap();
99 let found_grandchild = child_element.get_by_id("grandchild_node");
100 let found_child_not_exist = child_element.get_by_id("adfaf");
101 let found_button = container.get_by_tag_name("button");
102 assert!(found_grandchild.is_some());
103 assert!(found_child_not_exist.is_none());
104 assert!(found_button.is_some());
105 }
106}