parse_html/dom/
dom_tree.rs

1use crate::{
2    lexer::lexer_trait::LexerTrait,
3    node::{ElementNode, Node},
4    parser::{error::ParserError, parser_trait::ParserTrait},
5};
6
7use super::search::search_node_attr;
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
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn test_chainning() {
53        let grandchild_node = ElementNode {
54            tag_name: "div".to_string(),
55            attributes: vec![("id".to_string(), "grandchild_node".to_string())],
56            children: vec![],
57        };
58
59        let child_node = ElementNode {
60            tag_name: "div".to_string(),
61            attributes: vec![
62                ("id".to_string(), "child".to_string()),
63                ("class".to_string(), "space".to_string()),
64            ],
65            children: vec![Node::Element(grandchild_node)],
66        };
67
68        let parent_node = ElementNode {
69            tag_name: "div".to_string(),
70            attributes: vec![],
71            children: vec![Node::Element(child_node)],
72        };
73
74        let result_child = parent_node.get_by_class("space");
75        let child_element = result_child.unwrap();
76        let result_grandchild = child_element.get_by_id("grandchild_node");
77        let result_child_not_exist = child_element.get_by_id("adfaf");
78        assert!(result_grandchild.is_some());
79        assert!(result_child_not_exist.is_none());
80    }
81}