~chrisppy/go-opml

ref: v1.0.0 go-opml/opml.go -rw-r--r-- 2.9 KiB
d223d86fChris Palmer Add Package doc 3 months ago
                                                                                
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
// Package opml is an implementation of the OPML message format for Go.
//
// https://git.sr.ht/~chrisppy/go-opml
package opml

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"path/filepath"
	"strings"

	"golang.org/x/net/html/charset"
)

// OPML elements
type OPML struct {
	XMLName xml.Name `xml:"opml"`
	Version string   `xml:"version,attr"`
	Head    Head     `xml:"head"`
	Body    Body     `xml:"body"`
}

// Head Elements
type Head struct {
	XMLName         xml.Name `xml:"head"`
	Title           string   `xml:"title,omitempty"`
	DateCreated     string   `xml:"dateCreated,omitempty"`
	DateModified    string   `xml:"dateModified,omitempty"`
	OwnerName       string   `xml:"ownerName,omitempty"`
	OwnerEmail      string   `xml:"ownerEmail,omitempty"`
	OwnerID         string   `xml:"ownerId,omitempty"`
	Docs            string   `xml:"docs,omitempty"`
	ExpansionState  string   `xml:"expansionState,omitempty"`
	VertScrollState int      `xml:"vertScrollState,omitempty"`
	WindowTop       int      `xml:"windowTop,omitempty"`
	WindowLeft      int      `xml:"windowLeft,omitempty"`
	WindowBottom    int      `xml:"windowBottom,omitempty"`
	WindowRight     int      `xml:"windowRight,omitempty"`
}

// Body Elements
type Body struct {
	XMLName  xml.Name   `xml:"body"`
	Outlines []*Outline `xml:"outline"`
}

// Outline elements
type Outline struct {
	XMLName     xml.Name   `xml:"outline"`
	Text        string     `xml:"text,attr"`
	Description string     `xml:"description,attr,omitempty"`
	HTMLURL     string     `xml:"htmlUrl,attr,omitempty"`
	Language    string     `xml:"language,attr,omitempty"`
	Title       string     `xml:"title,attr,omitempty"`
	Type        string     `xml:"type,attr,omitempty"`
	Version     string     `xml:"version,attr,omitempty"`
	XMLURL      string     `xml:"xmlUrl,attr,omitempty"`
	Created     string     `xml:"created,attr,omitempty"`
	Outlines    []*Outline `xml:"outline"`
}

// FromFile will read the xml file
func FromFile(path string) (*OPML, error) {
	b, err := ioutil.ReadFile(filepath.Clean(path))
	if err != nil {
		return nil, err
	}
	r := bytes.NewReader(b)
	return Read(r)
}

// Read the xml from a reader
func Read(r io.Reader) (*OPML, error) {
	var o OPML
	decoder := xml.NewDecoder(r)
	decoder.CharsetReader = charset.NewReaderLabel
	if err := decoder.Decode(&o); err != nil {
		return nil, err
	}

	return &o, nil
}

// XML will convert the structure to XML
func (o *OPML) XML() ([]byte, error) {
	b := &bytes.Buffer{}
	enc := xml.NewEncoder(b)
	enc.Indent("", "\t")
	if err := enc.Encode(o); err != nil {
		return nil, err
	}

	s := fmt.Sprintf(`<?xml version="1.0" encoding="ISO-8859-1"?>
%s
`, b.String())

	s = strings.ReplaceAll(s, "></outline>", "/>")
	return []byte(s), nil
}

// Write the structure to a file as XML
func (o *OPML) Write(path string) error {
	b, err := o.XML()
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filepath.Clean(path), b, 0600)
}