-# $Id: RSS.pm 1934 2006-04-22 05:13:55Z btrott $
+# $Id$
package XML::Feed::Format::RSS;
use strict;
use base qw( XML::Feed );
use DateTime::Format::Mail;
use DateTime::Format::W3CDTF;
+use XML::Atom::Util qw(iso2dt);
+use XML::Feed::Enclosure;
+use XML::Feed::Entry::Format::RSS;
our $PREFERRED_PARSER = "XML::RSS";
my $feed = shift;
my($str) = @_;
$feed->init_empty;
+ my $opts = {
+ hashrefs_instead_of_strings => 1,
+ };
+ $opts->{allow_multiple} = [ 'enclosure' ] if $XML::Feed::MULTIPLE_ENCLOSURES;
if ($str) {
- $feed->{rss}->parse($$str);
+ $feed->{rss}->parse($$str, $opts );
}
$feed;
}
## The following elements are the same in all versions of RSS.
sub title { shift->{rss}->channel('title', @_) }
-sub link { shift->{rss}->channel('link', @_) }
+sub link {
+ my $link = shift->{rss}->channel('link', @_);
+ $link =~ s/^\s+//;
+ $link =~ s/\s+$//;
+ return $link;
+}
sub description { shift->{rss}->channel('description', @_) }
+sub updated { shift->modified(@_) }
# This doesn't exist in RSS
sub id { }
my $date;
eval {
if (my $ts = $rss->channel('pubDate')) {
+ $ts =~ s/^\s+//;
+ $ts =~ s/\s+$//;
$date = DateTime::Format::Mail->parse_datetime($ts);
} elsif ($ts = $rss->channel->{dc}{date}) {
+ $ts =~ s/^\s+//;
+ $ts =~ s/\s+$//;
$date = DateTime::Format::W3CDTF->parse_datetime($ts);
}
};
my @entries;
for my $item (@{ $rss->{items} }) {
push @entries, XML::Feed::Entry::Format::RSS->wrap($item);
+ $entries[-1]->{_version} = $rss->{'version'};
}
@entries;
}
sub as_xml { $_[0]->{rss}->as_string }
-package XML::Feed::Entry::Format::RSS;
-use strict;
-
-use XML::Feed::Content;
-
-use base qw( XML::Feed::Entry );
-
-sub init_empty { $_[0]->{entry} = { } }
-
-sub base {
- my $entry = shift;
- @_ ? $entry->{entry}->{'xml:base'} = $_[0] : $entry->{entry}->{'xml:base'};
-}
-
-sub title {
- my $entry = shift;
- @_ ? $entry->{entry}{title} = $_[0] : $entry->{entry}{title};
-}
-
-sub link {
- my $entry = shift;
- if (@_) {
- $entry->{entry}{link} = $_[0];
- ## For RSS 2.0 output from XML::RSS. Sigh.
- $entry->{entry}{permaLink} = $_[0];
- } else {
- $entry->{entry}{link} || $entry->{entry}{guid};
- }
-}
-
-sub summary {
- my $item = shift->{entry};
- if (@_) {
- $item->{description} = ref($_[0]) eq 'XML::Feed::Content' ?
- $_[0]->body : $_[0];
- ## Because of the logic below, we need to add some dummy content,
- ## so that we'll properly recognize the description we enter as
- ## the summary.
- if (!$item->{content}{encoded} &&
- !$item->{'http://www.w3.org/1999/xhtml'}{body}) {
- $item->{content}{encoded} = ' ';
- }
- } else {
- ## Some RSS feeds use <description> for a summary, and some use it
- ## for the full content. Pretty gross. We don't want to return the
- ## full content if the caller expects a summary, so the heuristic is:
- ## if the <entry> contains both a <description> and one of the elements
- ## typically used for the full content, use <description> as summary.
- my $txt;
- if ($item->{description} &&
- ($item->{content}{encoded} ||
- $item->{'http://www.w3.org/1999/xhtml'}{body})) {
- $txt = $item->{description};
- }
- XML::Feed::Content->wrap({ type => 'text/plain', body => $txt });
- }
-}
-
-sub content {
- my $item = shift->{entry};
- if (@_) {
- my $c;
- if (ref($_[0]) eq 'XML::Feed::Content') {
- if (defined $_[0]->base) {
- $c = { 'content' => $_[0]->body, 'xml:base' => $_[0]->base };
- } else {
- $c = $_[0]->body;
- }
- } else {
- $c = $_[0];
- }
- $item->{content}{encoded} = $c;
- } else {
- my $base;
- my $body =
- $item->{content}{encoded} ||
- $item->{'http://www.w3.org/1999/xhtml'}{body} ||
- $item->{description};
- if ('HASH' eq ref($body)) {
- $base = $body->{'xml:base'};
- $body = $body->{content};
- }
- XML::Feed::Content->wrap({ type => 'text/html', body => $body, base => $base });
- }
-}
-
-sub category {
- my $item = shift->{entry};
- if (@_) {
- $item->{category} = $item->{dc}{subject} = $_[0];
- } else {
- $item->{category} || $item->{dc}{subject};
- }
-}
-
-sub author {
- my $item = shift->{entry};
- if (@_) {
- $item->{author} = $item->{dc}{creator} = $_[0];
- } else {
- $item->{author} || $item->{dc}{creator};
- }
-}
-
-## XML::RSS doesn't give us access to the rdf:about for the <item>,
-## so we have to fall back to the <link> element in RSS 1.0 feeds.
-sub id {
- my $item = shift->{entry};
- if (@_) {
- $item->{guid} = $_[0];
- } else {
- $item->{guid} || $item->{link};
- }
-}
-
-sub issued {
- my $item = shift->{entry};
- if (@_) {
- $item->{dc}{date} = DateTime::Format::W3CDTF->format_datetime($_[0]);
- $item->{pubDate} = DateTime::Format::Mail->format_datetime($_[0]);
- } else {
- ## Either of these could die if the format is invalid.
- my $date;
- eval {
- if (my $ts = $item->{pubDate}) {
- my $parser = DateTime::Format::Mail->new;
- $parser->loose;
- $date = $parser->parse_datetime($ts);
- } elsif ($ts = $item->{dc}{date}) {
- $date = DateTime::Format::W3CDTF->parse_datetime($ts);
- }
- };
- return $date;
- }
-}
-
-sub modified {
- my $item = shift->{entry};
- if (@_) {
- $item->{dcterms}{modified} =
- DateTime::Format::W3CDTF->format_datetime($_[0]);
- } else {
- if (my $ts = $item->{dcterms}{modified}) {
- return eval { DateTime::Format::W3CDTF->parse_datetime($ts) };
- }
- }
-}
-
-sub lat {
- my $item = shift->{entry};
- if (@_) {
- $item->{geo}{lat} = $_[0];
- } else {
- return $item->{geo}{lat};
- }
-}
-
-sub long {
- my $item = shift->{entry};
- if (@_) {
- $item->{geo}{long} = $_[0];
- } else {
- return $item->{geo}{long};
- }
-}
-
-
1;
+