diff --git a/src/html5_parser/node_arena.rs b/src/html5_parser/node_arena.rs
index 7c7af3ebc..c33355fcd 100755
--- a/src/html5_parser/node_arena.rs
+++ b/src/html5_parser/node_arena.rs
@@ -37,6 +37,10 @@ impl NodeArena {
/// Add the node as a child the parent node
pub fn attach_node(&mut self, parent_id: usize, node_id: usize) {
+ //check if any children of node have parent as child
+ if parent_id == node_id || has_child_recursive(self,node_id,parent_id){
+ return;
+ }
if let Some(parent_node) = self.nodes.get_mut(&parent_id) {
parent_node.children.push(node_id);
}
@@ -64,6 +68,46 @@ impl NodeArena {
}
}
+fn has_child_recursive(arena: &mut NodeArena, parent_id: usize, child_id: usize) -> bool {
+ let node = arena.get_mut_node(parent_id).cloned();
+ if node.is_none(){
+ return false;
+ }
+ let node = node.unwrap();
+ for id in node.children.iter() {
+ if *id == child_id {
+ return true;
+ }
+ let child = arena.get_mut_node(*id).cloned();
+ if has_child(arena, child, child_id){
+ return true;
+ }
+ }
+ return false;
+}
+
+fn has_child(arena: &mut NodeArena, parent: Option, child_id: usize) -> bool {
+ let parent_node;
+ if parent.is_some(){
+ parent_node = parent.unwrap();
+ }
+ else {
+ return false; } if parent_node.children.len() == 0 {
+ return false;
+ }
+
+ for id in parent_node.children {
+ if id == child_id {
+ return true;
+ }
+ let node = arena.get_mut_node(id).cloned();
+ if has_child(arena, node, child_id){
+ return true;
+ }
+ }
+ return false;
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -116,6 +160,33 @@ mod tests {
assert_eq!(child.unwrap().parent, Some(parent_id));
}
+ #[test]
+ fn test_attach_node_to_itself(){
+ let mut arena = NodeArena::new();
+ let node = Node::new_element("some_node", HashMap::new(), HTML_NAMESPACE);
+ let node_id = arena.add_node(node);
+ arena.attach_node(node_id, node_id);
+ let node = arena.get_node(node_id);
+ assert!(node.is_some());
+ assert_eq!(node.unwrap().children.len(), 0);
+ }
+
+ #[test]
+ fn test_attach_node_with_loop_pointer(){
+ let mut arena = NodeArena::new();
+ let parent = Node::new_element("parent", HashMap::new(), HTML_NAMESPACE);
+ let mut child = Node::new_element("child", HashMap::new(), HTML_NAMESPACE);
+ let parent_id = arena.add_node(parent);
+ child.children.push(parent_id);
+ let child_id = arena.add_node(child);
+ arena.attach_node(parent_id, child_id);
+ let parent = arena.get_node(parent_id);
+ let child = arena.get_node(child_id);
+ assert!(parent.is_some());
+ assert!(child.is_some());
+ assert_eq!(parent.unwrap().children.len(), 0);
+ }
+
#[test]
fn test_remove_node() {
let mut arena = NodeArena::new();