3f992efd3c98f0091b16ad8da258c10e6ed4dc4c
[catagits/XML-Feed.git] / lib / XML / Feed / RSS.pm
1 # $Id: RSS.pm 942 2004-12-31 23:01:21Z btrott $
2
3 package XML::Feed::RSS;
4 use strict;
5
6 use base qw( XML::Feed );
7 use XML::RSS;
8 use DateTime::Format::Mail;
9 use DateTime::Format::W3CDTF;
10
11 sub init_string {
12     my $feed = shift;
13     my($str) = @_;
14     my $rss = $feed->{rss} = XML::RSS->new;
15     if ($str) {
16         $rss->parse($$str);
17     }
18     $feed;
19 }
20
21 sub format { 'RSS ' . $_[0]->{rss}->{'version'} }
22
23 ## The following elements are the same in all versions of RSS.
24 sub title { $_[0]->{rss}->channel('title') }
25 sub link { $_[0]->{rss}->channel('link') }
26 sub description { $_[0]->{rss}->channel('description') }
27
28 ## This is RSS 2.0 only--what's the equivalent in RSS 1.0?
29 sub copyright { $_[0]->{rss}->channel('copyright') }
30
31 ## The following all work transparently in any RSS version.
32 sub language {
33     $_[0]->{rss}->channel('language') ||
34     $_[0]->{rss}->channel->{dc}{language}
35 }
36
37 sub generator {
38     $_[0]->{rss}->channel('generator') ||
39     $_[0]->{rss}->channel->{'http://webns.net/mvcb/'}{generatorAgent};
40 }
41
42 sub author {
43     $_[0]->{rss}->channel('webMaster') ||
44     $_[0]->{rss}->channel->{dc}{creator};
45 }
46
47 sub modified {
48     my $rss = $_[0]->{rss};
49     if (my $ts = $rss->channel('pubDate')) {
50         return DateTime::Format::Mail->parse_datetime($ts);
51     } elsif ($ts = $rss->channel->{dc}{date}) {
52         return DateTime::Format::W3CDTF->parse_datetime($ts);
53     }
54 }
55
56 sub entries {
57     my $rss = $_[0]->{rss};
58     my @entries;
59     for my $item (@{ $rss->{items} }) {
60         push @entries, XML::Feed::RSS::Entry->wrap($item);
61     }
62     @entries;
63 }
64
65 package XML::Feed::RSS::Entry;
66 use strict;
67
68 use XML::Feed::Content;
69
70 use base qw( XML::Feed::Entry );
71
72 sub title { $_[0]->{entry}{title} }
73 sub link { $_[0]->{entry}{link} || $_[0]->{entry}{guid} }
74
75 sub summary {
76     my $item = $_[0]->{entry};
77     ## Some RSS feeds use <description> for a summary, and some use it
78     ## for the full content. Pretty gross. We don't want to return the
79     ## full content if the caller expects a summary, so the heuristic is:
80     ## if the <entry> contains both a <description> and one of the elements
81     ## typically used for the full content, use <description> as the summary.
82     my $txt;
83     if ($item->{description} &&
84         ($item->{'http://purl.org/rss/1.0/modules/content/'}{encoded} ||
85          $item->{'http://www.w3.org/1999/xhtml'}{body})) {
86         $txt = $item->{description};
87     }
88     XML::Feed::Content->wrap({ type => 'text/plain', body => $txt });
89 }
90
91 sub content {
92     my $item = $_[0]->{entry};
93     my $body =
94         $_[0]->{entry}{'http://purl.org/rss/1.0/modules/content/'}{encoded} ||
95         $_[0]->{entry}{'http://www.w3.org/1999/xhtml'}{body} ||
96         $_[0]->{entry}{description};
97     XML::Feed::Content->wrap({ type => 'text/html', body => $body });
98 }
99
100 sub category {
101     $_[0]->{entry}{category} || $_[0]->{entry}{dc}{subject};
102 }
103
104 sub author {
105     $_[0]->{entry}{author} || $_[0]->{entry}{dc}{creator};
106 }
107
108 ## XML::RSS doesn't give us access to the rdf:about for the <item>,
109 ## so we have to fall back to the <link> element in RSS 1.0 feeds.
110 sub id {
111     $_[0]->{entry}{guid} || $_[0]->{entry}{link};
112 }
113
114 sub issued {
115     if (my $ts = $_[0]->{entry}{pubDate}) {
116         my $parser = DateTime::Format::Mail->new;
117         $parser->loose;
118         return $parser->parse_datetime($ts);
119     } elsif ($ts = $_[0]->{entry}{dc}{date}) {
120         return DateTime::Format::W3CDTF->parse_datetime($ts);
121     }
122 }
123
124 sub modified {
125     if (my $ts = $_[0]->{entry}{'http://purl.org/rss/1.0/modules/dcterms/'}{modified}) {
126         return DateTime::Format::W3CDTF->parse_datetime($ts);
127     }
128 }
129
130 1;