Skip to content

Instantly share code, notes, and snippets.

@dav-m85
Created September 19, 2021 10:19
Show Gist options
  • Save dav-m85/4294e32d541ce57d62635b5b093bb1a9 to your computer and use it in GitHub Desktop.
Save dav-m85/4294e32d541ce57d62635b5b093bb1a9 to your computer and use it in GitHub Desktop.
Process .xbel files (XML Bookmark Exchange Language)
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