123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- package gofeed
- import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "net/http"
- "strings"
- "github.com/mmcdole/gofeed/atom"
- "github.com/mmcdole/gofeed/rss"
- )
- // HTTPError represents an HTTP error returned by a server.
- type HTTPError struct {
- StatusCode int
- Status string
- }
- func (err HTTPError) Error() string {
- return fmt.Sprintf("http error: %s", err.Status)
- }
- // Parser is a universal feed parser that detects
- // a given feed type, parsers it, and translates it
- // to the universal feed type.
- type Parser struct {
- AtomTranslator Translator
- RSSTranslator Translator
- Client *http.Client
- rp *rss.Parser
- ap *atom.Parser
- }
- // NewParser creates a universal feed parser.
- func NewParser() *Parser {
- fp := Parser{
- rp: &rss.Parser{},
- ap: &atom.Parser{},
- }
- return &fp
- }
- // Parse parses a RSS or Atom feed into
- // the universal gofeed.Feed. It takes an
- // io.Reader which should return the xml content.
- func (f *Parser) Parse(feed io.Reader) (*Feed, error) {
- // Wrap the feed io.Reader in a io.TeeReader
- // so we can capture all the bytes read by the
- // DetectFeedType function and construct a new
- // reader with those bytes intact for when we
- // attempt to parse the feeds.
- var buf bytes.Buffer
- tee := io.TeeReader(feed, &buf)
- feedType := DetectFeedType(tee)
- // Glue the read bytes from the detect function
- // back into a new reader
- r := io.MultiReader(&buf, feed)
- switch feedType {
- case FeedTypeAtom:
- return f.parseAtomFeed(r)
- case FeedTypeRSS:
- return f.parseRSSFeed(r)
- }
- return nil, errors.New("Failed to detect feed type")
- }
- // ParseURL fetches the contents of a given url and
- // attempts to parse the response into the universal feed type.
- func (f *Parser) ParseURL(feedURL string) (feed *Feed, err error) {
- client := f.httpClient()
- resp, err := client.Get(feedURL)
- if err != nil {
- return nil, err
- }
- if resp != nil {
- defer func() {
- ce := resp.Body.Close()
- if ce != nil {
- err = ce
- }
- }()
- }
- if resp.StatusCode < 200 || resp.StatusCode >= 300 {
- return nil, HTTPError{
- StatusCode: resp.StatusCode,
- Status: resp.Status,
- }
- }
- return f.Parse(resp.Body)
- }
- // ParseString parses a feed XML string and into the
- // universal feed type.
- func (f *Parser) ParseString(feed string) (*Feed, error) {
- return f.Parse(strings.NewReader(feed))
- }
- func (f *Parser) parseAtomFeed(feed io.Reader) (*Feed, error) {
- af, err := f.ap.Parse(feed)
- if err != nil {
- return nil, err
- }
- return f.atomTrans().Translate(af)
- }
- func (f *Parser) parseRSSFeed(feed io.Reader) (*Feed, error) {
- rf, err := f.rp.Parse(feed)
- if err != nil {
- return nil, err
- }
- return f.rssTrans().Translate(rf)
- }
- func (f *Parser) atomTrans() Translator {
- if f.AtomTranslator != nil {
- return f.AtomTranslator
- }
- f.AtomTranslator = &DefaultAtomTranslator{}
- return f.AtomTranslator
- }
- func (f *Parser) rssTrans() Translator {
- if f.RSSTranslator != nil {
- return f.RSSTranslator
- }
- f.RSSTranslator = &DefaultRSSTranslator{}
- return f.RSSTranslator
- }
- func (f *Parser) httpClient() *http.Client {
- if f.Client != nil {
- return f.Client
- }
- f.Client = &http.Client{}
- return f.Client
- }
|