-
Notifications
You must be signed in to change notification settings - Fork 0
/
bookmarks.go
129 lines (106 loc) · 2.4 KB
/
bookmarks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Golang library to work with bookmark export files in Netscape bookmark format
package bookmarks
import (
"io"
"golang.org/x/net/html"
)
// Parse html data and return a list of bookmarks and folders
// import (
// bookmarks "github.com/suhodolskiy/netscape-bookmarks"
// )
// func main() {
// input, _ := os.OpenFile("./example.html", os.O_RDONLY, 0644)
// data, _ := bookmarks.Parse(input)
// fmt.Println("Result", data)
// }
func Parse(r io.Reader) (Children, error) {
var c Children
n, err := html.Parse(r)
if err != nil {
return c, err
}
initialNode := findInitialNode(n)
if initialNode != nil && initialNode.FirstChild != nil {
parse(initialNode.FirstChild, &c)
}
return c, nil
}
// Recursive find for the first <DL> node
func findInitialNode(n *html.Node) *html.Node {
for c := n.FirstChild; c != nil; c = c.NextSibling {
if c.Data == "dl" {
return c
}
if n := findInitialNode(c); n != nil {
return n
}
}
return nil
}
func findNextDlNode(n *html.Node) *html.Node {
for c := n; c != nil; c = c.NextSibling {
if c.Data == "dl" {
return c
}
}
return nil
}
func parse(n *html.Node, result *Children) {
for c := n; c != nil; c = c.NextSibling {
if c.Type == html.TextNode {
continue
}
if c.Data == "dt" && c.FirstChild.Data == "h3" {
f := Folder{
Name: c.FirstChild.FirstChild.Data,
Attributes: []Attribute{},
}
for _, a := range c.FirstChild.Attr {
switch a.Key {
case attrAddDate:
{
f.AddDate = a.Val
}
case attrLastModified:
{
f.LastModified = a.Val
}
default:
f.Attributes = append(f.Attributes, Attribute{Key: a.Key, Value: a.Val})
}
}
if c.FirstChild != nil {
dl := findNextDlNode(c.FirstChild)
if dl != nil && dl.FirstChild != nil && dl.FirstChild.Data == "p" {
parse(dl.FirstChild, &f.Children)
}
}
*result = append(*result, f)
}
if c.Data == "dt" && c.FirstChild.Data == "a" {
b := Bookmark{
Name: c.FirstChild.FirstChild.Data,
Attributes: []Attribute{},
}
for _, a := range c.FirstChild.Attr {
switch a.Key {
case attrAddDate:
{
b.AddDate = a.Val
}
case attrIcon:
{
b.Icon = a.Val
}
case attrHref:
{
b.Href = a.Val
}
default:
b.Attributes = append(b.Attributes, Attribute{Key: a.Key, Value: a.Val})
}
}
*result = append(*result, b)
}
}
}