forked from ikeikeikeike/go-sitemap-generator
/
builder_url.go
129 lines (114 loc) · 3.53 KB
/
builder_url.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
package stm
import (
"errors"
"fmt"
"time"
"github.com/beevik/etree"
"github.com/fatih/structs"
)
// URLModel is specific sample model for valuedate.
// http://www.sitemaps.org/protocol.html
// https://support.google.com/webmasters/answer/178636
type URLModel struct {
Priority float64 `valid:"float,length(0.0|1.0)"`
Changefreq string `valid:"alpha(always|hourly|daily|weekly|monthly|yearly|never)"`
Lastmod time.Time `valid:"-"`
Expires time.Time `valid:"-"`
Host string `valid:"ipv4"`
Loc string `valid:"url"`
Image string `valid:"url"`
Video string `valid:"url"`
Tag string `valid:""`
Geo string `valid:""`
News string `valid:"-"`
Mobile bool `valid:"-"`
Alternate string `valid:"-"`
Alternates map[string]interface{} `valid:"-"`
Pagemap map[string]interface{} `valid:"-"`
}
// fieldnames []string{"priority" "changefreq" "lastmod" "expires" "host" "images"
// "video" "geo" "news" "videos" "mobile" "alternate" "alternates" "pagemap"}
var fieldnames = ToLowerString(structs.Names(&URLModel{}))
// NewSitemapURL returns the created the SitemapURL's pointer
// and it validates URL types error.
func NewSitemapURL(opts *Options, url URL) (SitemapURL, error) {
smu := &sitemapURL{opts: opts, data: url}
err := smu.validate()
return smu, err
}
// sitemapURL provides xml validator and xml builder.
type sitemapURL struct {
opts *Options
data URL
}
// validate is checking correct keys and checks the existence.
// TODO: Will create value's validator
func (su *sitemapURL) validate() error {
var key string
var invalid bool
var locOk, hostOk bool
for _, value := range su.data {
key = value[0].(string)
switch key {
case "loc":
locOk = true
case "host":
hostOk = true
}
invalid = true
for _, name := range fieldnames {
if key == name {
invalid = false
break
}
}
if invalid {
break
}
}
if invalid {
msg := fmt.Sprintf("Unknown map's key `%s` in URL type", key)
return errors.New(msg)
}
if !locOk {
msg := fmt.Sprintf("URL type must have `loc` map's key")
return errors.New(msg)
}
if !hostOk {
msg := fmt.Sprintf("URL type must have `host` map's key")
return errors.New(msg)
}
return nil
}
// XML is building xml.
func (su *sitemapURL) XML() []byte {
doc := etree.NewDocument()
url := doc.CreateElement("url")
SetBuilderElementValue(url, su.data.URLJoinBy("loc", "host", "loc"), "loc")
if _, ok := SetBuilderElementValue(url, su.data, "lastmod"); !ok && !su.opts.omitLastMod {
lastmod := url.CreateElement("lastmod")
lastmod.SetText(time.Now().Format(time.RFC3339))
}
if _, ok := SetBuilderElementValue(url, su.data, "changefreq"); !ok && !su.opts.omitChangeFreq {
changefreq := url.CreateElement("changefreq")
changefreq.SetText("weekly")
}
if _, ok := SetBuilderElementValue(url, su.data, "priority"); !ok && !su.opts.omitPriority {
priority := url.CreateElement("priority")
priority.SetText("0.5")
}
SetBuilderElementValue(url, su.data, "expires")
SetBuilderElementValue(url, su.data, "mobile")
SetBuilderElementValue(url, su.data, "news")
SetBuilderElementValue(url, su.data, "video")
SetBuilderElementValue(url, su.data, "image")
SetBuilderElementValue(url, su.data, "geo")
if su.opts.pretty {
doc.Indent(2)
}
buf := poolBuffer.Get()
doc.WriteTo(buf)
bytes := buf.Bytes()
poolBuffer.Put(buf)
return bytes
}