Created
September 19, 2021 10:19
-
-
Save dav-m85/4294e32d541ce57d62635b5b093bb1a9 to your computer and use it in GitHub Desktop.
Process .xbel files (XML Bookmark Exchange Language)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/xml" | |
"fmt" | |
"io/ioutil" | |
"net/http" | |
"os" | |
"strings" | |
) | |
const SUPPORTED_VERSION = "1.0" | |
const header = `<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE xbel PUBLIC "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML" "http://pyxml.sourceforge.net/topics/dtds/xbel.dtd"> | |
` | |
type XBEL struct { | |
XMLName xml.Name `xml:"xbel"` | |
Version string `xml:"version,attr"` | |
Folders []Folder `xml:"folder"` | |
} | |
type Folder struct { | |
Title string `xml:"title"` | |
ID int `xml:"id,attr"` | |
Folders []Folder `xml:"folder"` | |
Bookmarks []Bookmark `xml:"bookmark"` | |
} | |
type Bookmark struct { | |
Title string `xml:"title"` | |
ID int `xml:"id,attr"` | |
Href string `xml:"href,attr"` | |
} | |
type selector func(b *Bookmark) bool | |
func walk(x XBEL, s selector) XBEL { | |
var nf []Folder | |
for _, f := range x.Folders { | |
y := walkFolder(f, s) | |
// Skip empty folders | |
if len(y.Bookmarks) == 0 && len(y.Folders) == 0 { | |
continue | |
} | |
nf = append(nf, y) | |
} | |
return XBEL{ | |
XMLName: x.XMLName, | |
Version: SUPPORTED_VERSION, | |
Folders: nf, | |
} | |
} | |
// walkFolder apply s recursively to all bookmarks within | |
func walkFolder(x Folder, s selector) Folder { | |
var nb []Bookmark | |
for _, b := range x.Bookmarks { | |
if s(&b) { | |
nb = append(nb, b) | |
} | |
} | |
var nf []Folder | |
for _, f := range x.Folders { | |
y := walkFolder(f, s) | |
// Skip empty folders | |
if len(y.Bookmarks) == 0 && len(y.Folders) == 0 { | |
continue | |
} | |
nf = append(nf, y) | |
} | |
return Folder{ | |
Folders: nf, | |
Bookmarks: nb, | |
Title: x.Title, | |
ID: x.ID, | |
} | |
} | |
func check(err error) { | |
if err != nil { | |
panic(err) | |
} | |
} | |
func main() { | |
xmlFile, err := os.Open("bookmarks.xbel") | |
check(err) | |
defer xmlFile.Close() | |
byteValue, err := ioutil.ReadAll(xmlFile) | |
check(err) | |
var xbel XBEL | |
err = xml.Unmarshal(byteValue, &xbel) | |
check(err) | |
if xbel.Version != SUPPORTED_VERSION { | |
panic("unsupported XBEL version") | |
} | |
// nx := walk(xbel, func(b Bookmark) bool { | |
// fmt.Println(b.Href) | |
// return true | |
// }) | |
// Remove duplicates | |
hrefs := make(map[string]struct{}) | |
nx := walk(xbel, func(b *Bookmark) bool { | |
if _, exists := hrefs[b.Href]; exists { | |
// fmt.Println(b.Href) | |
return false | |
} | |
hrefs[b.Href] = struct{}{} | |
return true | |
}) | |
// os.Exit(1) | |
output, err := xml.MarshalIndent(nx, " ", " ") | |
if err != nil { | |
panic(err) | |
} | |
outFile, err := os.Create("out.xbel") | |
check(err) | |
defer outFile.Close() | |
outFile.Write([]byte(header)) | |
outFile.Write(output) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment