use crate::{
lexer::lexer_trait::LexerTrait,
node::{ElementNode, Node},
parser::{error::ParserError, parser_trait::ParserTrait},
};
use super::{
search_by_attr::{search_all_element_by_attr, search_element_by_attr},
search_by_tag_name::{search_all_element_by_tag_name, search_element_by_tag_name},
};
pub struct DomTree {
pub nodes: Vec<Node>,
}
impl DomTree {
pub fn new<L, P>(html: &str) -> Result<Self, ParserError>
where
L: LexerTrait,
P: ParserTrait,
{
let mut lexer = L::new(html);
let tokens = lexer.tokenize();
let mut parser = P::new(tokens);
let nodes = parser.parse()?;
Ok(Self { nodes })
}
pub fn get_by_id(&self, id_value: &str) -> Option<&ElementNode> {
for node in &self.nodes {
if let Some(found) = search_element_by_attr(node, "id", id_value) {
return Some(found);
}
}
None
}
pub fn get_all_by_id(&self, id_value: &str) -> Vec<&ElementNode> {
let mut list_found = vec![];
for node in &self.nodes {
list_found.extend(search_all_element_by_attr(node, "id", id_value));
}
list_found
}
pub fn get_by_class(&self, value: &str) -> Option<&ElementNode> {
for node in &self.nodes {
if let Some(found) = search_element_by_attr(node, "class", value) {
return Some(found);
}
}
None
}
pub fn get_all_by_class(&self, value: &str) -> Vec<&ElementNode> {
let mut list_found = vec![];
for node in &self.nodes {
list_found.extend(search_all_element_by_attr(node, "class", value));
}
list_found
}
pub fn get_by_tag_name(&self, tag_name: &str) -> Option<&ElementNode> {
for node in &self.nodes {
if let Some(found) = search_element_by_tag_name(node, tag_name) {
return Some(found);
}
}
None
}
pub fn get_all_by_tag_name(&self, tag_name: &str) -> Vec<&ElementNode> {
let mut list_found = vec![];
for node in &self.nodes {
list_found.extend(search_all_element_by_tag_name(node, tag_name));
}
list_found
}
pub fn get_by_attr(
&self,
attributes_name: &str,
attributes_value: &str,
) -> Option<&ElementNode> {
for node in &self.nodes {
if let Some(found) = search_element_by_attr(node, attributes_name, attributes_value) {
return Some(found);
}
}
None
}
pub fn get_all_by_attr(
&self,
attributes_name: &str,
attributes_value: &str,
) -> Vec<&ElementNode> {
let mut list_found = vec![];
for node in &self.nodes {
list_found.extend(search_all_element_by_attr(
node,
attributes_name,
attributes_value,
));
}
list_found
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_chainning() {
let grandchild_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![("id".to_string(), "grandchild_node".to_string())],
children: vec![],
};
let child_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![
("id".to_string(), "child".to_string()),
("class".to_string(), "space".to_string()),
],
children: vec![Node::Element(grandchild_node)],
};
let button = ElementNode {
tag_name: "button".to_string(),
attributes: vec![("class".to_string(), "btn".to_string())],
children: vec![Node::Text("envoyer".to_string())],
};
let parent_node = ElementNode {
tag_name: "div".to_string(),
attributes: vec![("class".to_string(), "mt-1".to_string())],
children: vec![Node::Element(child_node), Node::Element(button)],
};
let container = ElementNode {
tag_name: "div".to_string(),
attributes: vec![("class".to_string(), "container".to_string())],
children: vec![Node::Element(parent_node)],
};
let found_parent = container.get_by_class("mt-1");
let parent_element = found_parent.unwrap();
let found_child = parent_element.get_by_class("space");
let child_element = found_child.unwrap();
let found_grandchild = child_element.get_by_id("grandchild_node");
let found_child_not_exist = child_element.get_by_id("adfaf");
let found_button = container.get_by_tag_name("button");
let result_all_div_from_container = container.get_all_by_tag_name("div");
let result_all_button = container.get_all_by_tag_name("button");
let result_all_span = container.get_all_by_tag_name("span");
assert!(found_grandchild.is_some());
assert!(found_child_not_exist.is_none());
assert!(found_button.is_some());
assert!(result_all_div_from_container.len() == 3);
assert!(result_all_button.len() == 1);
assert!(result_all_span.len() == 0);
}
}