-# $Id: Feed.pm 1958 2006-08-14 05:31:27Z btrott $
+# $Id$
package XML::Feed;
use strict;
use URI::Fetch;
use LWP::UserAgent;
use Carp;
-
-our $VERSION = '0.23';
+use Module::Pluggable search_path => "XML::Feed::Format",
+ require => 1,
+ sub_name => 'formatters';
+
+our $VERSION = '0.44';
+our $MULTIPLE_ENCLOSURES = 0;
+our @formatters;
+BEGIN {
+ @formatters = __PACKAGE__->formatters;
+}
sub new {
my $class = shift;
my $format = shift || 'Atom';
- my $format_class = 'XML::Feed::' . $format;
+ my $format_class = 'XML::Feed::Format::' . $format;
eval "use $format_class";
Carp::croak("Unsupported format $format: $@") if $@;
- my $feed = bless {}, join('::', __PACKAGE__, $format);
+ my $feed = bless {}, join('::', __PACKAGE__, "Format", $format);
$feed->init_empty(@_) or return $class->error($feed->errstr);
$feed;
}
$format = $feed->identify_format(\$xml) or return $class->error($feed->errstr);
}
- my $format_class = join '::', __PACKAGE__, $format;
+ my $format_class = join '::', __PACKAGE__, "Format", $format;
eval "use $format_class";
return $class->error("Unsupported format $format: $@") if $@;
bless $feed, $format_class;
}
sub identify_format {
- my $feed = shift;
- my($xml) = @_;
+ my $feed = shift;
+ my($xml) = @_;
+ foreach my $class (@formatters) {
+ my ($name) = ($class =~ m!([^:]+)$!);
+ # TODO ugly
+ my $tmp = $$xml;
+ return $name if eval { $class->identify(\$tmp) };
+ return $feed->error($@) if $@;
+ }
+ return $feed->error("Cannot detect feed type");
+}
+
+sub _get_first_tag {
+ my $class = shift;
+ my ($xml) = @_;
+
+
## Auto-detect feed type based on first element. This is prone
## to breakage, but then again we don't want to parse the whole
## feed ourselves.
my $first = substr $t, 0, 1;
$tag = $t, last unless $first eq '?' || $first eq '!';
}
- return $feed->error("Cannot find first element") unless $tag;
+ die ("Cannot find first element") unless $tag;
$tag =~ s/^.*://;
- if ($tag eq 'rss' || $tag eq 'RDF') {
- return 'RSS';
- } elsif ($tag eq 'feed') {
- return 'Atom';
- } else {
- return $feed->error("Cannot detect feed type");
- }
+ return $tag;
}
sub find_feeds {
sub convert {
my $feed = shift;
my($format) = @_;
- my $new = __PACKAGE__->new($format);
+ my $new = XML::Feed->new($format);
for my $field (qw( title link description language author copyright modified generator )) {
my $val = $feed->$field();
next unless defined $val;
sub _convert_entry {
my $feed = shift;
my $entry = shift;
- my $feed_format = ref($feed); $feed_format =~ s!^XML::Feed::!!;
- my $entry_format = ref($entry); $entry_format =~ s!^XML::Feed::Entry::!!;
+ my $feed_format = ref($feed); $feed_format =~ s!^XML::Feed::Format::!!;
+ my $entry_format = ref($entry); $entry_format =~ s!^XML::Feed::Entry::Format::!!;
return $entry if $entry_format eq $feed_format;
return $entry->convert($feed_format);
}
B<Note:> this will only work for parsing feeds, not creating feeds.
+B<Note:> Only C<XML::RSS::LibXML> version 0.3004 is known to work at the moment.
+
+=item C<$XML::Feed::MULTIPLE_ENCLOSURES>
+
+Although the RSS specification states that there can be at most one enclosure per item
+some feeds break this rule.
+
+If this variable is set then C<XML::Feed> captures all of them and makes them available as a list.
+
+Otherwise it returns the last enclosure parsed.
+
+B<Note:> C<XML::RSS> version 1.44 is needed for this to work.
+
=back
+=cut
+
=head1 VALID FEEDS
For reference, this cgi script will create valid, albeit nonsensical feeds