Skip to content

Commit bdef2bb

Browse files
committed
Made GetParent fast. GetParent need be tested manually. GetParent and Closest test function passed.
1 parent 447b637 commit bdef2bb

File tree

4 files changed

+90
-17
lines changed

4 files changed

+90
-17
lines changed

node-tree.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,21 @@ func (node *Node) AppendChild(childNode *Node) {
115115

116116
lastNode := node.GetChildNode().GetLastNode()
117117
childNode.SetPreviousNode(lastNode)
118+
childNode.setParentNode(lastNode.GetParent())
118119
lastNode.SetNextNode(childNode)
119120
}
120121

121122
// Append inserts the newNode to end of the node chain.
122123
func (node *Node) Append(newNode *Node) {
123124
lastNode := node.GetLastNode()
124125
newNode.SetPreviousNode(lastNode)
126+
newNode.setParentNode(lastNode.GetParent())
125127
lastNode.SetNextNode(newNode)
126128
}
127129

128130
// GetParent returns a pointer to the parent node.
129131
func (node *Node) GetParent() *Node {
130-
return node.GetFirstNode().getParentNode()
132+
return node.parentNode
131133
}
132134

133135
// GetLastNode returns the last node in the node branch.

querying.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func (node *Node) QueryAll(query string) NodeList {
133133
}
134134

135135
/*
136-
QuerySearch tokenizes the query string and search for nodes that matches with the right most query token. After matching right most query it proceeds to match nodes parents nodes for left over tokens and then passed that node to (yield/range). QuerySearch search the whole node tree for matches unless yield get canceled or range iterator get cancel.
136+
QuerySearch tokenizes the query string and search for nodes that matches with the right most query token. After matching right most query it proceeds to match nodes parents nodes for left over tokens and then passed that node to (yield/range). QuerySearch search the whole node tree for matches unless yield get canceled or range iterator get cancel.
137137
*/
138138
func QuerySearch(node *Node, query string) iter.Seq[*Node] {
139139
return func(yield func(node *Node) bool) {
@@ -155,8 +155,8 @@ func QuerySearch(node *Node, query string) iter.Seq[*Node] {
155155
val, _ := stack.Pop()
156156
sf := val.(stackFrame)
157157

158-
for diff := len(parentNodeStack) - sf.len; len(parentNodeStack) > 0 && diff > 0; diff-- {
159-
_, parentNodeStack = pop(parentNodeStack)
158+
if sf.len <= len(parentNodeStack) {
159+
parentNodeStack = parentNodeStack[:sf.len]
160160
}
161161

162162
classList := NewClassList()
@@ -169,7 +169,8 @@ func QuerySearch(node *Node, query string) iter.Seq[*Node] {
169169
classList.DecodeFrom(node)
170170
i = matchFromRightMostQueryToken(node, classList, queryTokens, i-1)
171171
}
172-
if i < 0 && !yield(sf.node){
172+
173+
if i < 0 && !yield(sf.node) {
173174
return
174175
}
175176
}
@@ -183,7 +184,7 @@ func QuerySearch(node *Node, query string) iter.Seq[*Node] {
183184

184185
if sf.node.GetChildNode() != nil {
185186
childNode := sf.node.GetChildNode()
186-
parentNodeStack = append(parentNodeStack, childNode)
187+
parentNodeStack = append(parentNodeStack, sf.node)
187188
stack.Push(stackFrame{
188189
len: len(parentNodeStack),
189190
node: childNode,
@@ -209,9 +210,9 @@ outer:
209210
for i >= 0 {
210211
token := queryTokens[i]
211212
_, ok := checked[token.Selector]
212-
if ok{
213+
if ok {
213214
break
214-
}else{
215+
} else {
215216
checked[token.Selector] = struct{}{}
216217
}
217218

@@ -235,21 +236,21 @@ outer:
235236
return i
236237
}
237238

238-
//QuerySelector only returns the first node that matches with the QuerySearch.
239+
// QuerySelector only returns the first node that matches with the QuerySearch.
239240
func (node *Node) QuerySelector(query string) *Node {
240241
iter := QuerySearch(node, query)
241-
for node := range iter{
242+
for node := range iter {
242243
return node
243244
}
244245
return nil
245246
}
246247

247-
//QuerySelectorAll stores nodes passed down by QuerySearch in a nodeList and returns the nodeList.
248-
func (node *Node) QuerySelectorAll(query string) NodeList{
248+
// QuerySelectorAll stores nodes passed down by QuerySearch in a nodeList and returns the nodeList.
249+
func (node *Node) QuerySelectorAll(query string) NodeList {
249250
iter := QuerySearch(node, query)
250251
nodeList := NewNodeList()
251-
252-
for node := range iter{
252+
253+
for node := range iter {
253254
nodeList.Append(node)
254255
}
255256
return nodeList

querying_test.go

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,12 @@ func TestQueryAll(t *testing.T) {
188188
}
189189

190190
nodeList := node.QueryAll("h2")
191-
if nodeList.Len() != 2{
191+
if nodeList.Len() != 2 {
192192
t.Fatal("")
193193
}
194194
}
195195

196-
func TestQuerySelector(t *testing.T){
196+
func TestQuerySelector(t *testing.T) {
197197
node, err := testFile4NodeTree()
198198
if err != nil {
199199
t.Fatal(err)
@@ -202,6 +202,37 @@ func TestQuerySelector(t *testing.T){
202202
node = node.QuerySelector("html .ordered-list ol li .ordered-item")
203203
if node == nil {
204204
t.Fatal("Node is nill after QuerySelector")
205+
} else if node.GetInnerText() != "Apple" {
206+
t.Fatal("Unexpected text")
207+
}
208+
}
209+
210+
func TestQuerySelectorAll(t *testing.T) {
211+
node, err := testFile4NodeTree()
212+
if err != nil {
213+
t.Fatal(err)
214+
return
215+
}
216+
217+
nodeList := node.QuerySelectorAll(".unordered-list li")
218+
if nodeList.Len() == 0 {
219+
t.Fatal("Node list is empty")
220+
}else if nodeList.Len() != 3{
221+
t.Fatal("Extra node in the node list.", nodeList.Len())
222+
}
223+
stack := linkedliststack.New()
224+
stack.Push("Kottue")
225+
stack.Push("Pizza")
226+
stack.Push("Cake")
227+
228+
iter := nodeList.IterNodeList()
229+
for node := range iter{
230+
val, _ := stack.Pop()
231+
str := val.(string)
232+
if node.GetInnerText() != str{
233+
t.Fatal("Got unexpected text.", "Expected", str, "But got", node.GetInnerText())
234+
}else{
235+
t.Log(node.GetInnerText())
236+
}
205237
}
206-
t.Log(node.GetInnerText())
207238
}

test-files/5.html

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Tricky HTML</title>
5+
</head>
6+
<body>
7+
<div id="main" class="container highlight">
8+
<section>
9+
<article data-type="post" class="entry">
10+
<h2>First Post</h2>
11+
<p class="text">This is <span>some</span> tricky <em>HTML</em> code.</p>
12+
<a href="/readmore" class="btn primary">Read More</a>
13+
</article>
14+
15+
<article data-type="post draft" class="entry hidden">
16+
<h2>Second Post (Draft)</h2>
17+
<p class="text">Should be hidden but still queryable.</p>
18+
<a href="#" class="btn secondary disabled">Disabled Link</a>
19+
</article>
20+
</section>
21+
22+
<ul id="list">
23+
<li class="item">One</li>
24+
<li class="item special">Two <span>extra</span></li>
25+
<li class="item">Three</li>
26+
</ul>
27+
28+
<form id="login" action="/login">
29+
<input type="text" name="username" placeholder="User">
30+
<input type="password" name="password" placeholder="Pass">
31+
<button type="submit" disabled>Submit</button>
32+
</form>
33+
</div>
34+
35+
<footer>
36+
<p>&copy; <span id="year">2025</span> Example</p>
37+
</footer>
38+
</body>
39+
</html>

0 commit comments

Comments
 (0)