From 17bb6dc5fbc38e8f5f6b495cbd195eb34836a430 Mon Sep 17 00:00:00 2001 From: Udan Jayanith Jayakody Date: Sat, 2 Aug 2025 12:33:56 +0530 Subject: [PATCH 1/2] documentation and mutex bug fixes --- FUTURE-CHANGELOG.md | 2 +- main.go | 17 +------ node-tree.go | 113 ++++++++++++++++++++++++-------------------- test-files/3.html | 11 +++++ traverser.go | 4 +- 5 files changed, 78 insertions(+), 69 deletions(-) create mode 100644 test-files/3.html diff --git a/FUTURE-CHANGELOG.md b/FUTURE-CHANGELOG.md index 32c0e02..37b8e50 100644 --- a/FUTURE-CHANGELOG.md +++ b/FUTURE-CHANGELOG.md @@ -1,7 +1,7 @@ ## v0.0.0-beta.3 <- current ## v0.0.0 -Delete deletes the branch without connecting sibling nodes. +Delete deletes the node without connecting sibling nodes. * Delete QuerySelector takes attribute name and regexp for the value and returns the first node that matches the regexp. diff --git a/main.go b/main.go index de202ee..ae20325 100644 --- a/main.go +++ b/main.go @@ -49,7 +49,7 @@ func DeepCloneNode(node *Node) *Node{ return &newNode } -//CloneNode copy the node. +//CloneNode copy the node. But have one way connections to it's parent, next and previous nodes. func CloneNode(node *Node) *Node{ newNode := DeepCloneNode(node) newNode.setParentNode(node.getParentNode()) @@ -59,21 +59,6 @@ func CloneNode(node *Node) *Node{ return newNode } -//ApplySaveChanges replaces the nodes previous and parent node with the given node. -func ApplySaveChanges(node *Node){ - previousNode := node.GetPreviousNode() - if previousNode != nil{ - previousNode.SetNextNode(node) - } - - parentNode := node.getParentNode() - if parentNode != nil{ - parentNode.rwMutex.Lock() - parentNode.childNode = node - parentNode.rwMutex.Unlock() - } -} - func isQuote(chr string) bool { return chr == `"` || chr == `'` || chr == "`" } diff --git a/node-tree.go b/node-tree.go index af80c81..39986c7 100644 --- a/node-tree.go +++ b/node-tree.go @@ -5,7 +5,7 @@ import ( "sync" ) -//The DOM Node struct is an abstract base class upon which many other DOM API objects are based, thus letting +// The DOM Node struct is an abstract base class upon which many other DOM API objects are based, thus letting // those object types to be used similarly and often interchangeably. type Node struct { nextNode *Node @@ -16,86 +16,86 @@ type Node struct { tagName string attributes map[string]string text string - rwMutex sync.Mutex + rwMutex sync.Mutex } -//GetNextNode returns node next to the node. -func (node *Node) GetNextNode() *Node{ +// GetNextNode returns node next to the node. +func (node *Node) GetNextNode() *Node { node.rwMutex.Lock() defer node.rwMutex.Unlock() return node.nextNode } -//SetNextNode make nodes next node as nextNode. -func (node *Node) SetNextNode(nextNode *Node){ +// SetNextNode make nodes next node as nextNode. +func (node *Node) SetNextNode(nextNode *Node) { node.rwMutex.Lock() defer node.rwMutex.Unlock() node.nextNode = nextNode } -//GetPreviousNode returns the previous node. -func (node *Node) GetPreviousNode() *Node{ +// GetPreviousNode returns the previous node. +func (node *Node) GetPreviousNode() *Node { node.rwMutex.Lock() defer node.rwMutex.Unlock() return node.previousNode } -//SetPreviousNode sets nodes previous node to previousNode. -func (node *Node) SetPreviousNode(previousNode *Node){ +// SetPreviousNode sets nodes previous node to previousNode. +func (node *Node) SetPreviousNode(previousNode *Node) { node.rwMutex.Lock() defer node.rwMutex.Unlock() node.previousNode = previousNode } -//GetChildNode returns the first child elements of this node. -func (node *Node) GetChildNode() *Node{ +// GetChildNode returns the first child elements of this node. +func (node *Node) GetChildNode() *Node { node.rwMutex.Lock() defer node.rwMutex.Unlock() return node.childNode } -//getParentNode returns parent node. -func (node *Node) getParentNode() *Node{ +// getParentNode returns parent node. +func (node *Node) getParentNode() *Node { node.rwMutex.Lock() defer node.rwMutex.Unlock() return node.parentNode } -func (node *Node) setParentNode(parentNode *Node){ +func (node *Node) setParentNode(parentNode *Node) { node.rwMutex.Lock() defer node.rwMutex.Unlock() node.parentNode = parentNode } -//Returns a string with the name of the tag for the given node. -func (node *Node) GetTagName() string{ +// Returns a string with the name of the tag for the given node. +func (node *Node) GetTagName() string { node.rwMutex.Lock() defer node.rwMutex.Unlock() - if strings.ToUpper(node.tagName) == DOCTYPEDTD{ + if strings.ToUpper(node.tagName) == DOCTYPEDTD { return strings.ToUpper(node.tagName) } return node.tagName } -//SetTagName changes the html tag name to the tagName. -func (node *Node) SetTagName(tagName string){ +// SetTagName changes the html tag name to the tagName. +func (node *Node) SetTagName(tagName string) { node.rwMutex.Lock() defer node.rwMutex.Unlock() node.tagName = strings.TrimSpace(strings.ToLower(tagName)) } -//GetAttribute returns the specified attribute value form the node. -func (node *Node) GetAttribute(attributeName string) (string, bool){ +// GetAttribute returns the specified attribute value form the node. If the specified attribute doesn't exists GetAttribute returns a empty string and false. +func (node *Node) GetAttribute(attributeName string) (string, bool) { node.rwMutex.Lock() defer node.rwMutex.Unlock() @@ -103,49 +103,50 @@ func (node *Node) GetAttribute(attributeName string) (string, bool){ return v, ok } -//RemoveAttribute remove or delete the specified attribute. -func (node *Node) RemoveAttribute(attributeName string){ +// RemoveAttribute remove or delete the specified attribute. +func (node *Node) RemoveAttribute(attributeName string) { node.rwMutex.Lock() defer node.rwMutex.Unlock() delete(node.attributes, attributeName) } -//IterateAttributes calls callback at every attribute in the node by passing attribute and value of the each node to the callback. -func (node *Node) IterateAttributes(callback func(attribute, value string)){ +// IterateAttributes calls callback at every attribute in the node by passing attribute and value of the node. +func (node *Node) IterateAttributes(callback func(attribute, value string)) { node.rwMutex.Lock() - defer node.rwMutex.Unlock() + attributes := node.attributes + node.rwMutex.Unlock() - for k, v := range node.attributes{ + for k, v := range attributes { callback(k, v) } } -//SetAttribute add a attribute to the node. -func (node *Node) SetAttribute(attribute, value string){ +// SetAttribute add a attribute to the node. +func (node *Node) SetAttribute(attribute, value string) { node.rwMutex.Lock() defer node.rwMutex.Unlock() node.attributes[strings.TrimSpace(attribute)] = strings.TrimSpace(value) } -//GetText returns text on the node. This does not returns text on it's child nodes. If you also wants child nodes text use GetInnerText method on the node. -func (node *Node) GetText() string{ +// GetText returns text on the node. This does not returns text on it's child nodes. If you also wants child nodes text use GetInnerText method on the node. +func (node *Node) GetText() string { node.rwMutex.Lock() defer node.rwMutex.Unlock() return node.text } -//SetText add text to the node. -func (node *Node) SetText(text string){ +// SetText add text to the node. +func (node *Node) SetText(text string) { node.rwMutex.Lock() defer node.rwMutex.Unlock() node.text = text } -//The AppendChild() method of the Node adds a node to the end of the list of children of a specified parent node. +// The AppendChild() method of the Node adds a node to the end of the list of children of a specified parent node. func (node *Node) AppendChild(childNode *Node) { if node.GetChildNode() == nil { node.rwMutex.Lock() @@ -161,20 +162,20 @@ func (node *Node) AppendChild(childNode *Node) { lastNode.SetNextNode(childNode) } -//Append inserts the newNode to end of the node chain. +// Append inserts the newNode to end of the node chain. func (node *Node) Append(newNode *Node) { lastNode := node.GetLastNode() newNode.SetPreviousNode(lastNode) lastNode.SetNextNode(newNode) } -//GetParent returns a pointer to the parent node. +// GetParent returns a pointer to the parent node. func (node *Node) GetParent() *Node { return node.GetFirstNode().getParentNode() } -//GetLastNode returns the last node in the node branch. -func (node *Node) GetLastNode() *Node{ +// GetLastNode returns the last node in the node branch. +func (node *Node) GetLastNode() *Node { traverser := GetTraverser(node) for traverser.GetCurrentNode().GetNextNode() != nil { traverser.Next() @@ -182,29 +183,29 @@ func (node *Node) GetLastNode() *Node{ return traverser.GetCurrentNode() } -//GetFirstNode returns the first node of the node branch. -func (node *Node) GetFirstNode() *Node{ +// GetFirstNode returns the first node of the node branch. +func (node *Node) GetFirstNode() *Node { traverser := GetTraverser(node) - for traverser.GetCurrentNode().GetPreviousNode() != nil{ + for traverser.GetCurrentNode().GetPreviousNode() != nil { traverser.Previous() } return traverser.GetCurrentNode() } -//AppendText add text to the node. -func (node *Node) AppendText(text string){ +// AppendText append text to the node. +func (node *Node) AppendText(text string) { textNode := CreateNode("") textNode.SetText(text) - if node.GetTagName() == "" || IsVoidTag(node.GetTagName()){ + if node.GetTagName() == "" || IsVoidTag(node.GetTagName()) { node.GetLastNode().Append(textNode) return } node.GetLastNode().AppendChild(textNode) } -//GetInnerText returns all of the text inside the node. -func (node *Node) GetInnerText() string{ +// GetInnerText returns all of the text inside the node. +func (node *Node) GetInnerText() string { text := "" traverser := GetTraverser(node.childNode) traverser.Walkthrough(func(node *Node) TraverseCondition { @@ -218,10 +219,9 @@ func (node *Node) GetInnerText() string{ return text } -//RemoveNode removes the node from the branch safely. -func (node *Node) RemoveNode(){ +// RemoveNode removes the node from the branch safely by connecting sibling nodes. +func (node *Node) RemoveNode() { node.rwMutex.Lock() - defer node.rwMutex.Unlock() previousNode := node.previousNode nextNode := node.nextNode @@ -229,6 +229,8 @@ func (node *Node) RemoveNode(){ node.previousNode = nil node.nextNode = nil + node.rwMutex.Unlock() + if previousNode != nil { previousNode.SetNextNode(nextNode) } @@ -237,6 +239,17 @@ func (node *Node) RemoveNode(){ } } +// DeleteNode removes the node without connecting sibling nodes. +func (node *Node) DeleteNode() { + node.rwMutex.Lock() + defer node.rwMutex.Unlock() + + node.previousNode = nil + node.nextNode = nil + node.parentNode = nil +} + +// IsTextNode returns a boolean value indicating node is a text node or not. func (node *Node) IsTextNode() bool { return node.GetTagName() == "" } diff --git a/test-files/3.html b/test-files/3.html new file mode 100644 index 0000000..26815ec --- /dev/null +++ b/test-files/3.html @@ -0,0 +1,11 @@ + + + + + Simple Page + + +

Hello, World!

+

This is a simple HTML page.

+ + diff --git a/traverser.go b/traverser.go index 8f8b7c2..caa0f7f 100644 --- a/traverser.go +++ b/traverser.go @@ -54,8 +54,8 @@ const ( ContinueWalkthrough TraverseCondition = false ) -//TODO: use a linked stack -//Walkthrough traverse the node tree from the current node to the end of the node tree by visiting every node. If callback returned StopWalkthrough walkthrough function will stop else if it returned ContinueWalkthrough it continues walkthrough until every node is visited. +//Walkthrough traverse the node tree from the current node to the end of the node tree by visiting every node. If callback returned StopWalkthrough walkthrough function will stop else if it returned ContinueWalkthrough it advanced to the next node. +//Walkthrough calls callback at every node and pass that node. Walkthrough traverse the node tree similar to DFS without visiting visited nodes iteratively. func (t *Traverser) Walkthrough(callback func(node *Node) TraverseCondition) { stack := linkedliststack.New() stack.Push(t.GetCurrentNode()) From a07c3e43379dd41dec1f2ae45e8b42a8a17e2bce Mon Sep 17 00:00:00 2001 From: Udan Jayanith Jayakody Date: Sat, 2 Aug 2025 12:43:27 +0530 Subject: [PATCH 2/2] bug fixes --- node-tree.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/node-tree.go b/node-tree.go index 39986c7..559f19a 100644 --- a/node-tree.go +++ b/node-tree.go @@ -225,6 +225,7 @@ func (node *Node) RemoveNode() { previousNode := node.previousNode nextNode := node.nextNode + parentNode := node.parentNode node.previousNode = nil node.nextNode = nil @@ -237,16 +238,10 @@ func (node *Node) RemoveNode() { if nextNode != nil { nextNode.SetPreviousNode(previousNode) } -} - -// DeleteNode removes the node without connecting sibling nodes. -func (node *Node) DeleteNode() { - node.rwMutex.Lock() - defer node.rwMutex.Unlock() - node.previousNode = nil - node.nextNode = nil - node.parentNode = nil + if nextNode != nil{ + nextNode.setParentNode(parentNode) + } } // IsTextNode returns a boolean value indicating node is a text node or not.