diff --git a/src/html5/parser/document.rs b/src/html5/parser/document.rs index 15384a0e..78dbbd8a 100755 --- a/src/html5/parser/document.rs +++ b/src/html5/parser/document.rs @@ -298,7 +298,7 @@ impl Document { self.arena.get_node_mut(*node_id) } - /// Retrieves the next sibling NodeId (to the right) of the current node or None. + /// Retrieves the next sibling NodeId (to the right) of the reference_node or None. pub fn get_next_sibling(&self, reference_node: NodeId) -> Option { let node = self.get_node_by_id(reference_node)?; let parent = self.get_node_by_id(node.parent?)?; @@ -312,6 +312,7 @@ impl Document { if parent.children.len() > idx + 1 { return Some(parent.children[idx + 1]); } + None } @@ -437,6 +438,21 @@ impl Document { pub fn has_cyclic_reference(&self, node_id: NodeId, parent_id: NodeId) -> bool { has_child_recursive(&self.arena, node_id, parent_id) } + + /// Check if a given node's children contain a certain tag name + pub fn contains_child_tag(&self, node_id: NodeId, tag: &str) -> bool { + if let Some(node) = self.get_node_by_id(node_id) { + for child_id in &node.children { + if let Some(child) = self.get_node_by_id(*child_id) { + if child.name == tag { + return true; + } + } + } + } + + false + } } /// Returns true when the parent node has the child node as a child, or if any of the children of @@ -712,6 +728,55 @@ impl DocumentHandle { Ok(()) } + fn check_query_predicate( + &self, + doc_read: &Document, + current_node: &Node, + condition: &Condition, + ) -> bool { + match condition { + Condition::EqualsTag(tag) => current_node.name == *tag, + Condition::EqualsId(id) => { + let node_data = ¤t_node.data; + if let NodeData::Element(element) = node_data { + if let Some(id_attr) = element.attributes.get("id") { + return *id_attr == *id; + } + } + + false + } + Condition::ContainsClass(class) => { + let node_data = ¤t_node.data; + if let NodeData::Element(element) = node_data { + return element.classes.contains(class.as_str()); + } + + false + } + Condition::ContainsAttribute(attribute) => { + let node_data = ¤t_node.data; + if let NodeData::Element(element) = node_data { + return element.attributes.contains_key(attribute); + } + + false + } + Condition::ContainsChildTag(child_tag) => { + doc_read.contains_child_tag(current_node.id, child_tag) + } + Condition::HasParentTag(parent_tag) => { + if let Some(parent_id) = current_node.parent { + // making an assumption here that the parent node is actually valid + let parent = doc_read.get_node_by_id(parent_id).unwrap(); + return parent.name == *parent_tag; + } + + false + } + } + } + /// Perform a single query against the document. /// If query search type is uninitialized, returns an error. /// Otherwise, returns a vector of NodeIds that match the predicate in tree order (preorder depth-first.) @@ -743,16 +808,9 @@ impl DocumentHandle { let mut predicate_result: bool = true; for condition in &query.conditions { - match condition { - Condition::EqualsTag(tag) => { - if current_node.name != *tag { - predicate_result = false; - } - } - // TODO: implement remaining conditions - _ => { - predicate_result = false; - } + if !self.check_query_predicate(&doc_read, current_node, condition) { + predicate_result = false; + break; } }