Skip to content

Commit

Permalink
Merge pull request #5 from mingard/feat/date-format
Browse files Browse the repository at this point in the history
Add date format
  • Loading branch information
mingard authored Nov 9, 2022
2 parents c954f22 + 0362881 commit df51b45
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 37 deletions.
34 changes: 34 additions & 0 deletions date.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package sitemap

import (
"encoding/xml"
"time"
)

const (
shortFormat string = "2006-01-02"
fullFormat string = "2006-01-02T15:04:05-07:00"
)

// customDate is a time.Time value with custom XML unmarshal method.
type customDate struct {
time.Time
format string
}

// MarshalXML is a customer marshal method for customDate.
func (c *customDate) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
t := time.Time(c.Time)
v := t.Format(c.format)
return e.EncodeElement(v, start)
}

// Date returns a new short format date.
func Date(t time.Time) customDate {
return customDate{t, shortFormat}
}

// DateFull returns a long format date.
func DateFull(t time.Time) customDate {
return customDate{t, fullFormat}
}
22 changes: 11 additions & 11 deletions location.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import (

// Location is a location block to be nested under the parent node.
type Location struct {
XMLName xml.Name `xml:"url,omitempty"`
Location string `xml:"loc,omitempty"`
ChangeFrequency string `xml:"changefreq,omitempty"`
Priority string `xml:"priority,omitempty"`
LastModifiedDate time.Time `xml:"lastmod,omitempty"`
News *News `xml:"news:news,omitempty"`
Images []*Image `xml:"image:image,omitempty"`
Videos []*Video `xml:"video:video,omitempty"`
XMLName xml.Name `xml:"url,omitempty"`
Location string `xml:"loc,omitempty"`
ChangeFrequency string `xml:"changefreq,omitempty"`
Priority string `xml:"priority,omitempty"`
LastModifiedDate customDate `xml:"lastmod,omitempty"`
News *News `xml:"news:news,omitempty"`
Images []*Image `xml:"image:image,omitempty"`
Videos []*Video `xml:"video:video,omitempty"`
}

// isSitemapIndex sets the XML node name to 'sitemap'
Expand All @@ -30,8 +30,8 @@ func (l *Location) SetLocation(loc string) {
}

// SetLastModified sets the value of the modified date field.
func (l *Location) SetLastModified(t time.Time) {
l.LastModifiedDate = t.UTC()
func (l *Location) SetLastModified(c customDate) {
l.LastModifiedDate = c
}

// SetNews sets the single news sub-node.
Expand All @@ -57,7 +57,7 @@ func defaultLoc() *Location {
Images: make([]*Image, 0),
Videos: make([]*Video, 0),
}
url.SetLastModified(now)
url.SetLastModified(Date(now))
return url
}

Expand Down
8 changes: 4 additions & 4 deletions news.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
type News struct {
XMLName xml.Name `xml:"news:news"`
Publication *Publication `xml:"news:publication"`
PublicationDate time.Time `xml:"news:publication_date"`
PublicationDate customDate `xml:"news:publication_date"`
Title string `xml:"news:title"`
}

Expand All @@ -29,8 +29,8 @@ func (n *News) SetName(na string) *News {
}

// SetPublicationDate sets the news extensions PublicationDate parameter.
func (n *News) SetPublicationDate(t time.Time) *News {
n.PublicationDate = t.UTC()
func (n *News) SetPublicationDate(c customDate) *News {
n.PublicationDate = c
return n
}

Expand All @@ -56,7 +56,7 @@ func defaultNews() *News {
NewsLanguage: LangDefault,
},
}
return n.SetPublicationDate(now)
return n.SetPublicationDate(Date(now))
}

// NewNews returns a new instance of the default News extension.
Expand Down
17 changes: 8 additions & 9 deletions video.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package sitemap
import (
"encoding/xml"
"strings"
"time"
)

const (
Expand Down Expand Up @@ -61,14 +60,14 @@ type Video struct {
// Duration value must be from {{DurationMin}} to {{DurationMax}} inclusive.
Duration int `xml:"video:duration,omitempty"`
// ExpirationDate format either YYYY-MM-DD or YYYY-MM-DDThh:mm:ss+TZD
ExpirationDate time.Time `xml:"video:expiration_date,omitempty"`
ExpirationDate customDate `xml:"video:expiration_date,omitempty"`

// Optional

// Rating values are float numbers in the range {{RatingLow}} (low) to {{RatingHigh}} (high), inclusive.
Rating float32 `xml:"video:rating,omitempty"`
ViewCount int `xml:"video:view_count,omitempty"`
PublicationDate time.Time `xml:"video:publication_date,omitempty"`
Rating float32 `xml:"video:rating,omitempty"`
ViewCount int `xml:"video:view_count,omitempty"`
PublicationDate customDate `xml:"video:publication_date,omitempty"`
// FamilyFriendly whether the video is available with SafeSearch.
FamilyFriendly BoolStr `xml:"video:family_friendly,omitempty"`
Restrictions []*Restriction `xml:"video:restriction,omitempty"`
Expand Down Expand Up @@ -126,8 +125,8 @@ func (v *Video) SetDuration(d int) *Video {
}

// SetExpirationDate sets the video ExpirationDate parameter.
func (v *Video) SetExpirationDate(t time.Time) *Video {
v.ExpirationDate = t.UTC()
func (v *Video) SetExpirationDate(c customDate) *Video {
v.ExpirationDate = c
return v
}

Expand All @@ -146,8 +145,8 @@ func (v *Video) SetViewCount(vc int) *Video {
}

// SetPublicationDate sets the video extensions PublicationDate parameter.
func (v *Video) SetPublicationDate(t time.Time) *Video {
v.PublicationDate = t.UTC()
func (v *Video) SetPublicationDate(c customDate) *Video {
v.PublicationDate = c
return v
}

Expand Down
1 change: 1 addition & 0 deletions xml.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func (x *XML) Add(l *Location) {
// Output returns the output value as bytes
func (x *XML) Output() ([]byte, error) {
x.applyXMLNS()

out := []byte(x.headerString())
var err error

Expand Down
59 changes: 46 additions & 13 deletions xml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import (
const (
testDefaultXML string = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"></urlset>`
testDefaultSitemapIndexXML string = `<?xml version="1.0" encoding="UTF-8"?><sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"></sitemapindex>`
testDefaultPrettyXML string = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\nXXXXX<url>\nXXXXXXXXXX<lastmod>2021-08-15T14:30:45.0000001Z</lastmod>\nXXXXX</url>\n</urlset>"
testFullNewsXML string = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"><url><lastmod>2021-08-15T14:30:45.0000001Z</lastmod><news:news><news:publication><news:name>SOMENAME</news:name><news:language>en</news:language></news:publication><news:publication_date>2021-08-15T14:30:45.0000001Z</news:publication_date><news:title>TITLE</news:title></news:news></url></urlset>`
testFullImageXML string = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"><url><loc>https://somedomain.com/article</loc><lastmod>2021-08-15T14:30:45.0000001Z</lastmod><image:image><image:loc>https://somedomain.com/image.jpg</image:loc></image:image></url></urlset>`
testFullVideoXML string = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"><url><loc>https://somedomain.com/article</loc><lastmod>2021-08-15T14:30:45.0000001Z</lastmod><video:video><video:title>Some title</video:title><video:thumbnail_loc>https://somedomain.com/thumb.jpg</video:thumbnail_loc><video:content_loc>https://somedomain.com/video.mp4</video:content_loc><video:player_loc>https://somedomain.com/player</video:player_loc><video:duration>100</video:duration><video:expiration_date>2021-08-15T14:30:45.0000001Z</video:expiration_date><video:rating>2</video:rating><video:view_count>100</video:view_count><video:publication_date>2021-08-15T14:30:45.0000001Z</video:publication_date></video:video></url></urlset>`
testDefaultPrettyXML string = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\nXXXXX<url>\nXXXXXXXXXX<lastmod>2021-08-15</lastmod>\nXXXXX</url>\n</urlset>"
testFullNewsXML string = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"><url><lastmod>2021-08-15</lastmod><news:news><news:publication><news:name>SOMENAME</news:name><news:language>en</news:language></news:publication><news:publication_date>2021-08-15</news:publication_date><news:title>TITLE</news:title></news:news></url></urlset>`
testFullImageXML string = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"><url><loc>https://somedomain.com/article</loc><lastmod>2021-08-15</lastmod><image:image><image:loc>https://somedomain.com/image.jpg</image:loc></image:image></url></urlset>`
testFullVideoXML string = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"><url><loc>https://somedomain.com/article</loc><lastmod>2021-08-15</lastmod><video:video><video:title>Some title</video:title><video:thumbnail_loc>https://somedomain.com/thumb.jpg</video:thumbnail_loc><video:content_loc>https://somedomain.com/video.mp4</video:content_loc><video:player_loc>https://somedomain.com/player</video:player_loc><video:duration>100</video:duration><video:expiration_date>2021-08-15</video:expiration_date><video:rating>2</video:rating><video:view_count>100</video:view_count><video:publication_date>2021-08-15</video:publication_date></video:video></url></urlset>`
)

var fixedTime = time.Date(2021, 8, 15, 14, 30, 45, 100, time.UTC)
Expand Down Expand Up @@ -81,7 +81,7 @@ func TestPrettyOutput(t *testing.T) {
xml := New()

loc := NewLoc()
loc.SetLastModified(fixedTime)
loc.SetLastModified(Date(fixedTime))
xml.Add(loc)

out, _ := xml.OutputPrettyString("", "XXXXX")
Expand Down Expand Up @@ -136,11 +136,11 @@ func TestSetNews(t *testing.T) {
func TestSetNewsValues(t *testing.T) {
xml := New()
loc := NewLoc()
loc.SetLastModified(fixedTime)
loc.SetLastModified(Date(fixedTime))
news := NewNews()
news.SetTitle("TITLE")
news.SetName("SOMENAME")
news.SetPublicationDate(fixedTime)
news.SetPublicationDate(Date(fixedTime))
news.SetLanguage(LanguageEN)
loc.SetNews(news)
xml.Add(loc)
Expand All @@ -166,7 +166,7 @@ func TestAddImageValues(t *testing.T) {
xml := New()
loc := NewLoc()
loc.SetLocation("https://somedomain.com/article")
loc.SetLastModified(fixedTime)
loc.SetLastModified(Date(fixedTime))

image := NewImage()
image.SetLocation("https://somedomain.com/image.jpg")
Expand All @@ -193,18 +193,18 @@ func TestAddVideoValues(t *testing.T) {
xml := New()
loc := NewLoc()
loc.SetLocation("https://somedomain.com/article")
loc.SetLastModified(fixedTime)
loc.SetLastModified(Date(fixedTime))

video := NewVideo()
video.SetTitle("Some title")
video.SetThumbnailLocation("https://somedomain.com/thumb.jpg")
video.SetContentLocation("https://somedomain.com/video.mp4")
video.SetPlayerLocation("https://somedomain.com/player")
video.SetDuration(100)
video.SetExpirationDate(fixedTime)
video.SetExpirationDate(Date(fixedTime))
video.SetRating(2)
video.SetViewCount(100)
video.SetPublicationDate(fixedTime)
video.SetPublicationDate(Date(fixedTime))
loc.AddVideo(video)
xml.Add(loc)

Expand Down Expand Up @@ -398,7 +398,7 @@ func TestXMLAddEntryWithLastModified(t *testing.T) {

now := time.Now()
later := now.Add(3 * time.Hour)
loc.SetLastModified(later)
loc.SetLastModified(Date(later))
xml.Add(loc)

out, _ := xml.OutputString()
Expand All @@ -407,5 +407,38 @@ func TestXMLAddEntryWithLastModified(t *testing.T) {
assert.True(t, tag != nil, "Should have lastmod set")

nodeTime, _ := time.Parse(time.RFC3339, tag.InnerText())
assert.Equal(t, nodeTime, later.UTC(), "Should match input timestamp")
laterFormat, _ := time.Parse(shortFormat, later.String())
assert.Equal(t, nodeTime, laterFormat, "Should match input timestamp")
}

func TestDate(t *testing.T) {
xml := New()
loc := NewLoc()

now := time.Now()
loc.SetLastModified(Date(now))
xml.Add(loc)

out, _ := xml.OutputString()

tag, _ := findOne(out, "//urlset/url/lastmod")
assert.True(t, tag != nil, "Should have lastmod set")

assert.Equal(t, tag.InnerText(), now.Format(shortFormat), "Should format a short date")
}

func TestDateFull(t *testing.T) {
xml := New()
loc := NewLoc()

now := time.Now()
loc.SetLastModified(DateFull(now))
xml.Add(loc)

out, _ := xml.OutputString()

tag, _ := findOne(out, "//urlset/url/lastmod")
assert.True(t, tag != nil, "Should have lastmod set")

assert.Equal(t, tag.InnerText(), now.Format(fullFormat), "Should format a long date")
}

0 comments on commit df51b45

Please sign in to comment.