1package feeds 2 3import ( 4 "encoding/json" 5 "encoding/xml" 6 "io" 7 "sort" 8 "time" 9) 10 11type Link struct { 12 Href, Rel, Type, Length string 13} 14 15type Author struct { 16 Name, Email string 17} 18 19type Image struct { 20 Url, Title, Link string 21 Width, Height int 22} 23 24type Enclosure struct { 25 Url, Length, Type string 26} 27 28type Item struct { 29 Title string 30 Link *Link 31 Source *Link 32 Author *Author 33 Description string // used as description in rss, summary in atom 34 Id string // used as guid in rss, id in atom 35 Updated time.Time 36 Created time.Time 37 Enclosure *Enclosure 38 Content string 39} 40 41type Feed struct { 42 Title string 43 Link *Link 44 Description string 45 Author *Author 46 Updated time.Time 47 Created time.Time 48 Id string 49 Subtitle string 50 Items []*Item 51 Copyright string 52 Image *Image 53} 54 55// add a new Item to a Feed 56func (f *Feed) Add(item *Item) { 57 f.Items = append(f.Items, item) 58} 59 60// returns the first non-zero time formatted as a string or "" 61func anyTimeFormat(format string, times ...time.Time) string { 62 for _, t := range times { 63 if !t.IsZero() { 64 return t.Format(format) 65 } 66 } 67 return "" 68} 69 70// interface used by ToXML to get a object suitable for exporting XML. 71type XmlFeed interface { 72 FeedXml() interface{} 73} 74 75// turn a feed object (either a Feed, AtomFeed, or RssFeed) into xml 76// returns an error if xml marshaling fails 77func ToXML(feed XmlFeed) (string, error) { 78 x := feed.FeedXml() 79 data, err := xml.MarshalIndent(x, "", " ") 80 if err != nil { 81 return "", err 82 } 83 // strip empty line from default xml header 84 s := xml.Header[:len(xml.Header)-1] + string(data) 85 return s, nil 86} 87 88// WriteXML writes a feed object (either a Feed, AtomFeed, or RssFeed) as XML into 89// the writer. Returns an error if XML marshaling fails. 90func WriteXML(feed XmlFeed, w io.Writer) error { 91 x := feed.FeedXml() 92 // write default xml header, without the newline 93 if _, err := w.Write([]byte(xml.Header[:len(xml.Header)-1])); err != nil { 94 return err 95 } 96 e := xml.NewEncoder(w) 97 e.Indent("", " ") 98 return e.Encode(x) 99} 100 101// creates an Atom representation of this feed 102func (f *Feed) ToAtom() (string, error) { 103 a := &Atom{f} 104 return ToXML(a) 105} 106 107// WriteAtom writes an Atom representation of this feed to the writer. 108func (f *Feed) WriteAtom(w io.Writer) error { 109 return WriteXML(&Atom{f}, w) 110} 111 112// creates an Rss representation of this feed 113func (f *Feed) ToRss() (string, error) { 114 r := &Rss{f} 115 return ToXML(r) 116} 117 118// WriteRss writes an RSS representation of this feed to the writer. 119func (f *Feed) WriteRss(w io.Writer) error { 120 return WriteXML(&Rss{f}, w) 121} 122 123// ToJSON creates a JSON Feed representation of this feed 124func (f *Feed) ToJSON() (string, error) { 125 j := &JSON{f} 126 return j.ToJSON() 127} 128 129// WriteJSON writes an JSON representation of this feed to the writer. 130func (f *Feed) WriteJSON(w io.Writer) error { 131 j := &JSON{f} 132 feed := j.JSONFeed() 133 134 e := json.NewEncoder(w) 135 e.SetIndent("", " ") 136 return e.Encode(feed) 137} 138 139// Sort sorts the Items in the feed with the given less function. 140func (f *Feed) Sort(less func(a, b *Item) bool) { 141 lessFunc := func(i, j int) bool { 142 return less(f.Items[i], f.Items[j]) 143 } 144 sort.SliceStable(f.Items, lessFunc) 145} 146