// Package rss implements RSS fetcher package rss import ( "encoding/xml" "errors" "net/http" "strings" "time" "golang.org/x/net/html/charset" ) // RSS container type RSS struct { Version string `xml:"version,attr"` Channel Channel `xml:"channel"` } // Time in RFC1123Z or RFC1123 format type Time struct { time.Time } // Channel container type Channel struct { Link string `xml:"link"` Language string `xml:"language"` Title string `xml:"title"` Description string `xml:"description"` PubDate Time `xml:"pubDate"` Items []Item `xml:"item"` } // Item container type Item struct { Author string `xml:"author"` Link string `xml:"link"` GUID string `xml:"guid"` Title string `xml:"title"` PubDate Time `xml:"pubDate"` } var formats = []string{ `Mon, _2 Jan 2006 15:04:05 -0700`, // like RFC1123Z `Mon, _2 Jan 2006 15:04:05 MST`, // like RFC1123 } // UnmarshalXML decodes Time format func (t *Time) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { var v string d.DecodeElement(&v, &start) v = strings.TrimSpace(v) for _, f := range formats { if parse, err := time.Parse(f, v); err == nil { *t = Time{parse} return nil } } return errors.New(v) } // Fetch and parse RSS from given URL func Fetch(url string) (rss RSS, err error) { resp, err := http.Get(url) if err != nil { return rss, err } defer resp.Body.Close() decoder := xml.NewDecoder(resp.Body) decoder.CharsetReader = charset.NewReaderLabel err = decoder.Decode(&rss) if err != nil { return rss, err } return rss, nil }