3a589c9950fc7916f91cf3b687e0258b110892ad
[catagits/XML-Feed.git] / lib / XML / Feed / Format / RSS.pm
1 # $Id$
2
3 package XML::Feed::Format::RSS;
4 use strict;
5
6 use base qw( XML::Feed );
7 use DateTime::Format::Mail;
8 use DateTime::Format::W3CDTF;
9 use XML::Atom::Util qw(iso2dt);
10 use XML::Feed::Enclosure;
11 use XML::Feed::Entry::Format::RSS;
12
13 our $PREFERRED_PARSER = "XML::RSS";
14
15
16 sub identify {
17     my $class   = shift;
18     my $xml     = shift;
19     my $tag     = $class->_get_first_tag($xml);
20     return ($tag eq 'rss' || $tag eq 'RDF');
21 }
22
23 sub init_empty {
24     my ($feed, %args) = @_;
25     $args{'version'} ||= '2.0';
26     eval "use $PREFERRED_PARSER"; die $@ if $@;
27     $feed->{rss} = $PREFERRED_PARSER->new(%args);
28     $feed->{rss}->add_module(prefix => "content", uri => 'http://purl.org/rss/1.0/modules/content/');
29     $feed->{rss}->add_module(prefix => "dcterms", uri => 'http://purl.org/dc/terms/');    
30     $feed->{rss}->add_module(prefix => "atom", uri => 'http://www.w3.org/2005/Atom');
31     $feed->{rss}->add_module(prefix => "geo", uri => 'http://www.w3.org/2003/01/geo/wgs84_pos#');
32     $feed;
33 }
34
35 sub init_string {
36     my $feed = shift;
37     my($str) = @_;
38     $feed->init_empty;
39     my $opts = {
40          hashrefs_instead_of_strings => 1,
41     };
42     $opts->{allow_multiple} = [ 'enclosure' ] if $XML::Feed::MULTIPLE_ENCLOSURES;
43     if ($str) {
44         $feed->{rss}->parse($$str, $opts );
45     }
46     $feed;
47 }
48
49 sub format { 'RSS ' . $_[0]->{rss}->{'version'} }
50
51 ## The following elements are the same in all versions of RSS.
52 sub title       { shift->{rss}->channel('title', @_) }
53 sub link        {
54     my $link = shift->{rss}->channel('link', @_);
55     $link =~ s/^\s+//;
56     $link =~ s/\s+$//;
57     return $link;
58 }
59 sub description { shift->{rss}->channel('description', @_) }
60 sub updated     { shift->modified(@_) }
61
62 # This doesn't exist in RSS
63 sub id          { }
64
65 ## This is RSS 2.0 only--what's the equivalent in RSS 1.0?
66 sub copyright   { shift->{rss}->channel('copyright', @_) }
67
68 sub base {
69     my $feed = shift;
70     if (@_) {
71         $feed->{rss}->{'xml:base'} = $_[0];
72     } else {
73         $feed->{rss}->{'xml:base'};
74     }
75 }
76
77 ## The following all work transparently in any RSS version.
78 sub language {
79     my $feed = shift;
80     if (@_) {
81         $feed->{rss}->channel('language', $_[0]);
82         $feed->{rss}->channel->{dc}{language} = $_[0];
83     } else {
84         $feed->{rss}->channel('language') ||
85         $feed->{rss}->channel->{dc}{language};
86     }
87 }
88
89 sub self_link {
90     my $feed = shift;
91
92     if (@_) {
93         my $uri = shift;
94
95         $feed->{rss}->channel->{'atom'}{'link'} =
96         {
97             rel => "self",
98             href => $uri,
99             type => "application/rss+xml",
100         };
101     }
102
103     return $feed->{rss}->channel->{'atom'}{'link'};
104 }
105
106
107 sub generator {
108     my $feed = shift;
109     if (@_) {
110         $feed->{rss}->channel('generator', $_[0]);
111         $feed->{rss}->channel->{'http://webns.net/mvcb/'}{generatorAgent} =
112             $_[0];
113     } else {
114         $feed->{rss}->channel('generator') ||
115         $feed->{rss}->channel->{'http://webns.net/mvcb/'}{generatorAgent};
116     }
117 }
118
119 sub author {
120     my $feed = shift;
121     if (@_) {
122         $feed->{rss}->channel('webMaster', $_[0]);
123         $feed->{rss}->channel->{dc}{creator} = $_[0];
124     } else {
125         $feed->{rss}->channel('webMaster') ||
126         $feed->{rss}->channel->{dc}{creator};
127     }
128 }
129
130 sub modified {
131     my $rss = shift->{rss};
132     if (@_) {
133         $rss->channel('pubDate',
134             DateTime::Format::Mail->format_datetime($_[0]));
135         ## XML::RSS is so weird... if I set this, it will try to use
136         ## the value for the lastBuildDate, which I don't want--because
137         ## this date is formatted for an RSS 1.0 feed. So it's commented out.
138         #$rss->channel->{dc}{date} =
139         #    DateTime::Format::W3CDTF->format_datetime($_[0]);
140     } else {
141         my $date;
142         eval {
143             if (my $ts = $rss->channel('pubDate')) {
144                 $ts =~ s/^\s+//;
145                 $ts =~ s/\s+$//;
146                 $date = DateTime::Format::Mail->parse_datetime($ts);
147             } elsif ($ts = $rss->channel->{dc}{date}) {
148                 $ts =~ s/^\s+//;
149                 $ts =~ s/\s+$//;
150                 $date = DateTime::Format::W3CDTF->parse_datetime($ts);
151             }
152         };
153         return $date;
154     }
155 }
156
157 sub entries {
158     my $rss = $_[0]->{rss};
159     my @entries;
160     for my $item (@{ $rss->{items} }) {
161         push @entries, XML::Feed::Entry::Format::RSS->wrap($item);
162                 $entries[-1]->{_version} = $rss->{'version'};           
163     }
164     @entries;
165 }
166
167 sub add_entry {
168     my $feed  = shift;
169     my $entry = shift || return;
170     $entry    = $feed->_convert_entry($entry);
171     $feed->{rss}->add_item(%{ $entry->unwrap });
172 }
173
174 sub as_xml { $_[0]->{rss}->as_string }
175
176 1;
177