feed.go (3235B)
1 package feeds 2 3 import ( 4 "encoding/json" 5 "encoding/xml" 6 "io" 7 "sort" 8 "time" 9 ) 10 11 type Link struct { 12 Href, Rel, Type, Length string 13 } 14 15 type Author struct { 16 Name, Email string 17 } 18 19 type Image struct { 20 Url, Title, Link string 21 Width, Height int 22 } 23 24 type Enclosure struct { 25 Url, Length, Type string 26 } 27 28 type 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 41 type 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 56 func (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 "" 61 func 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. 71 type 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 77 func 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. 90 func 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 102 func (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. 108 func (f *Feed) WriteAtom(w io.Writer) error { 109 return WriteXML(&Atom{f}, w) 110 } 111 112 // creates an Rss representation of this feed 113 func (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. 119 func (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 124 func (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. 130 func (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. 140 func (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 }