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::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}