Skip to content

Commit 06ba0af

Browse files
Merge pull request #12 from udan-jayanith/0.2.3
0.2.3
2 parents 519a50e + bc870b7 commit 06ba0af

23 files changed

+650
-224
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
{
22
"cSpell.words": [
3+
"arraystack",
34
"autoplay",
5+
"Combinators",
46
"DOCTYPEDTD",
57
"emirpasic",
68
"gohtml",
79
"Kottue",
810
"linkedliststack",
11+
"println",
912
"yosssi"
1013
]
1114
}

FUTURE-CHANGELOG.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
## v0.0.3
2-
- Closest
1+

README.md

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,35 +27,27 @@ import (
2727
- Querying
2828

2929
## Example
30+
3031
Heres an example of fetching a website and parsing and then using querying methods.
32+
3133
```go
3234
res, err := http.Get("https://www.metalsucks.net/")
3335
if err != nil {
3436
t.Fatal(err)
3537
}
3638
defer res.Body.Close()
3739

38-
//Parses the given html reader and then returns the root node and an error.
3940
node, err := GoHtml.Decode(res.Body)
4041
if err != nil {
4142
t.Fatal(err)
4243
}
4344

44-
nodeList := node.GetElementsByClassName("post-title")
45-
iter := nodeList.IterNodeList()
46-
for node := range iter{
47-
print(node.GetInnerText())
45+
nodeList := node.QuerySelectorAll(".left-content article .post-title")
46+
for node := range nodeList.IterNodeList(){
47+
println(node.GetInnerText())
4848
}
4949
```
5050

51-
## Changelog
52-
53-
Changes, bug fixes and new features in this version.
54-
- add: Tokenizer
55-
- add: NodeTreeBuilder
56-
- renamed: QuerySelector to Query
57-
- renamed: QuerySelectorAll to QueryAll
58-
5951
## Documentation
6052

6153
Fully fledged [documentation](https://pkg.go.dev/github.com/udan-jayanith/GoHTML) is available at [go.pkg](https://pkg.go.dev/)

benchmarks/benchmark_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import(
66
"net/http"
77
"time"
88
)
9-
9+
/*
10+
Adapted from [GoQuery example](https://github.com/PuerkitoBio/goquery?tab=readme-ov-file#examples)
11+
*/
1012
func TestFetchPostCovers(t *testing.T){
1113
res, err := http.Get("https://www.metalsucks.net/")
1214
if err != nil {
@@ -20,7 +22,7 @@ func TestFetchPostCovers(t *testing.T){
2022
t.Fatal(err)
2123
}
2224

23-
nodeList := node.QueryAll(".sm-feat .clearfix article")
25+
nodeList := node.QuerySelectorAll(".left-content article .post-title")
2426
t.Log("Got ", nodeList.Len(), " post titles.")
2527
iter := nodeList.IterNodeList()
2628
for node := range iter{

classList.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (classList ClassList) Encode() string {
6868
return classes
6969
}
7070

71-
// EncodeTo encode className for the node.
71+
// EncodeTo encodes classNames for the node.
7272
// If node is nil EncodeTo does nothing.
7373
func (classList ClassList) EncodeTo(node *Node){
7474
if node == nil {

classList_test.go

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,63 @@
11
package GoHtml_test
22

3-
import(
3+
import (
4+
"fmt"
45
"testing"
5-
"github.com/udan-jayanith/GoHTML"
6+
7+
GoHtml "github.com/udan-jayanith/GoHTML"
68
)
79

8-
func TestClasses(t *testing.T){
10+
func TestClasses(t *testing.T) {
911
node := GoHtml.CreateNode("div")
1012
node.SetAttribute("class", "div-container main")
1113

1214
classList := GoHtml.NewClassList()
1315
classList.DecodeFrom(node)
14-
if !classList.Contains("main"){
16+
if !classList.Contains("main") {
1517
t.Fatal("")
1618
return
1719
}
1820
classList.DeleteClass("main")
19-
if classList.Contains("main"){
21+
if classList.Contains("main") {
2022
t.Fatal("")
2123
return
2224
}
2325

2426
classList.AppendClass("main-div")
25-
if !classList.Contains("main-div"){
27+
if !classList.Contains("main-div") {
2628
t.Fatal("")
2729
return
2830
}
2931

3032
classList.EncodeTo(node)
33+
}
34+
35+
func ExampleClassList_Contains() {
36+
//Creates a div that has classes video-container and main-contents
37+
div := GoHtml.CreateNode("div")
38+
div.SetAttribute("class", "video-container main-contents")
39+
40+
classList := GoHtml.NewClassList()
41+
//Add the classes in the div to the class list
42+
classList.DecodeFrom(div)
43+
44+
//Checks wether the following classes exists in the classList
45+
fmt.Println(classList.Contains("container"))
46+
fmt.Println(classList.Contains("video-container"))
47+
48+
//Output:
49+
//false
50+
//true
51+
}
52+
53+
func ExampleClassList_Encode(){
54+
classList := GoHtml.NewClassList()
55+
56+
//Add classes to the class list
57+
classList.AppendClass("container")
58+
classList.AppendClass("warper")
59+
classList.AppendClass("main-content")
60+
61+
//This would output something like this "warper container main-content". Order of the output is not guaranteed.
62+
fmt.Println(classList.Encode())
3163
}

node-list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"iter"
66
)
77

8-
//NodeList can store nodes by appended order.
8+
//NodeList can store nodes by appended order and can iterate over the node list by invoking IterNodeList method.
99
type NodeList struct {
1010
list *list.List
1111
currentEl *list.Element

node-list_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package GoHtml_test
22

33
import (
4+
"fmt"
45
"os"
56
"testing"
67

@@ -13,6 +14,7 @@ func TestIterNodeList1(t *testing.T) {
1314
t.Fatal(err)
1415
return
1516
}
17+
defer file.Close()
1618

1719
node, err := GoHtml.Decode(file)
1820
if err != nil {
@@ -39,4 +41,20 @@ func TestIterNodeList2(t *testing.T){
3941
for node := range iter{
4042
t.Log(node)
4143
}
44+
}
45+
46+
func ExampleNodeList(){
47+
nodeList := GoHtml.NewNodeList()
48+
nodeList.Append(GoHtml.CreateNode("br"))
49+
nodeList.Append(GoHtml.CreateNode("hr"))
50+
nodeList.Append(GoHtml.CreateNode("div"))
51+
52+
iter := nodeList.IterNodeList()
53+
for node := range iter{
54+
fmt.Println(node.GetTagName())
55+
}
56+
//Output:
57+
//br
58+
//hr
59+
//div
4260
}

node-tree.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package GoHtml
22

33
import (
44
"strings"
5+
56
"golang.org/x/net/html"
67
)
78

@@ -38,7 +39,7 @@ func (node *Node) SetPreviousNode(previousNode *Node) {
3839
node.previousNode = previousNode
3940
}
4041

41-
// GetChildNode returns the first child elements of this node.
42+
// GetChildNode returns the first child node of this node.
4243
func (node *Node) GetChildNode() *Node {
4344
return node.childNode
4445
}
@@ -75,7 +76,7 @@ func (node *Node) GetAttribute(attributeName string) (string, bool) {
7576
// RemoveAttribute remove or delete the specified attribute.
7677
func (node *Node) RemoveAttribute(attributeName string) {
7778
delete(node.attributes, strings.TrimSpace(strings.ToLower(attributeName)))
78-
79+
7980
}
8081

8182
// IterateAttributes calls callback at every attribute in the node by passing attribute and value of the node.
@@ -114,19 +115,21 @@ func (node *Node) AppendChild(childNode *Node) {
114115

115116
lastNode := node.GetChildNode().GetLastNode()
116117
childNode.SetPreviousNode(lastNode)
118+
childNode.setParentNode(lastNode.GetParent())
117119
lastNode.SetNextNode(childNode)
118120
}
119121

120122
// Append inserts the newNode to end of the node chain.
121123
func (node *Node) Append(newNode *Node) {
122124
lastNode := node.GetLastNode()
123125
newNode.SetPreviousNode(lastNode)
126+
newNode.setParentNode(lastNode.GetParent())
124127
lastNode.SetNextNode(newNode)
125128
}
126129

127130
// GetParent returns a pointer to the parent node.
128131
func (node *Node) GetParent() *Node {
129-
return node.GetFirstNode().getParentNode()
132+
return node.parentNode
130133
}
131134

132135
// GetLastNode returns the last node in the node branch.
@@ -203,3 +206,21 @@ func (node *Node) RemoveNode() {
203206
func (node *Node) IsTextNode() bool {
204207
return node.GetTagName() == ""
205208
}
209+
210+
// Closest traverses the node tree and its parents (heading toward the root node) until it finds a node that matches the selector and returns that node.
211+
// Adapted from [https://developer.mozilla.org/en-US/docs/Web/API/Element/closest](MDN Element: closest() method)
212+
func (node *Node) Closest(selector string) *Node {
213+
traverser := NewTraverser(node)
214+
selectors := TokenizeSelectorsAndCombinators(selector)
215+
216+
for traverser.GetCurrentNode() != nil {
217+
if matchFromRightMostSelectors(traverser.GetCurrentNode(), selectors) {
218+
break
219+
} else if traverser.GetCurrentNode().GetPreviousNode() == nil {
220+
traverser.SetCurrentNodeTo(traverser.GetCurrentNode().GetParent())
221+
} else {
222+
traverser.Previous()
223+
}
224+
}
225+
return traverser.GetCurrentNode()
226+
}

node-tree_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,24 @@ func TestRemoveNode(t *testing.T){
112112

113113
//p.RemoveNode()
114114
//t.Log(GoHtml.NodeTreeToHTML(article))
115+
}
116+
117+
func TestClosest(t *testing.T){
118+
node, err := testFile4NodeTree()
119+
if err != nil{
120+
t.Fatal(err)
121+
}
122+
node = node.GetElementByClassName("ordered-item")
123+
if node == nil {
124+
t.Fatal("Node is nil.")
125+
}
126+
127+
node = node.Closest("img+.ordered-list")
128+
if node == nil {
129+
t.Fatal("Node is nil")
130+
}else if node.GetTagName() != "ol"{
131+
t.Fatal("Unexpected element.")
132+
}
133+
134+
115135
}

0 commit comments

Comments
 (0)