Update tests
[catagits/XML-Feed.git] / lib / XML / Feed / Format / Atom.pm
1 # $Id: Atom.pm 1958 2006-08-14 05:31:27Z btrott $
2
3 package XML::Feed::Format::Atom;
4 use strict;
5
6 use base qw( XML::Feed );
7 use XML::Atom::Feed;
8 use XML::Atom::Util qw( iso2dt );
9 use List::Util qw( first );
10 use DateTime::Format::W3CDTF;
11
12 use XML::Atom::Entry;
13 XML::Atom::Entry->mk_elem_accessors(qw( lat long ), ['http://www.w3.org/2003/01/geo/wgs84_pos#']);
14
15 use XML::Atom::Content;
16
17 sub identify {
18         my $class   = shift;
19         my $xml     = shift;
20         my $tag     = $class->_get_first_tag($xml);
21         return ($tag eq 'feed');
22 }
23
24 sub init_empty {
25     my ($feed, %args) = @_;
26     $args{'Version'} ||= '1.0';
27     
28     $feed->{atom} = XML::Atom::Feed->new(%args);
29     $feed;
30 }
31
32 # monkey patch
33 {
34     my $sub =  sub {
35         my $item = shift;
36         if (XML::Atom::LIBXML) {
37             my $elem = $item->elem;
38             if (@_) {
39                 $elem->setAttributeNS('http://www.w3.org/XML/1998/namespace',
40                     'base', $_[0]);
41             }
42             return $elem->getAttributeNS('http://www.w3.org/XML/1998/namespace', 'base');
43         } else {
44             if (@_) {
45                 $item->elem->setAttribute('xml:base', $_[0]);
46             }
47             return $item->elem->getAttribute('xml:base');
48         }
49
50     };
51     no strict 'refs';
52     *XML::Atom::Feed::base    = $sub unless XML::Atom::Feed->can('base');
53     *XML::Atom::Entry::base   = $sub unless XML::Atom::Entry->can('base');
54     *XML::Atom::Content::base = $sub unless XML::Atom::Content->can('base');
55 }
56
57 sub init_string {
58     my $feed = shift;
59     my($str) = @_;
60     if ($str) {
61         $feed->{atom} = XML::Atom::Feed->new(Stream => $str)
62             or return $feed->error(XML::Atom::Feed->errstr);
63     }
64     $feed;
65 }
66
67 sub format { 'Atom' }
68
69 sub title { shift->{atom}->title(@_) }
70 sub link {
71     my $feed = shift;
72     if (@_) {
73         $feed->{atom}->add_link({ rel => 'alternate', href => $_[0],
74                                   type => 'text/html', });
75     } else {
76         my $l = first { !defined $_->rel || $_->rel eq 'alternate' } $feed->{atom}->link;
77         $l ? $l->href : undef;
78     }
79 }
80
81 sub self_link {
82     my $feed = shift;
83     if (@_) {
84         my $uri = shift;
85         $feed->{atom}->add_link({type => "application/atom+xml", rel => "self", href => $uri});
86         return $uri;
87     } 
88     else
89     {
90         my $l =
91             first
92             { !defined $_->rel || $_->rel eq 'self' }
93             $feed->{atom}->link;
94             ;
95
96         return $l ? $l->href : undef;
97     }
98 }
99
100 sub description { shift->{atom}->tagline(@_) }
101 sub copyright   { shift->{atom}->copyright(@_) }
102 sub language    { shift->{atom}->language(@_) }
103 sub generator   { shift->{atom}->generator(@_) }
104 sub id          { shift->{atom}->id(@_) }
105 sub updated     { shift->{atom}->updated(@_) }
106 sub add_link    { shift->{atom}->add_link(@_) }
107 sub base        { shift->{atom}->base(@_) }
108
109 sub author {
110     my $feed = shift;
111     if (@_ && $_[0]) {
112         my $person = XML::Atom::Person->new(Version => 1.0);
113         $person->name($_[0]);
114         $feed->{atom}->author($person);
115     } else {
116         $feed->{atom}->author ? $feed->{atom}->author->name : undef;
117     }
118 }
119
120
121
122
123 sub modified {
124     my $feed = shift;
125     if (@_) {
126         $feed->{atom}->modified(DateTime::Format::W3CDTF->format_datetime($_[0]));
127     } else {
128         return iso2dt($feed->{atom}->modified) if $feed->{atom}->modified;
129         return iso2dt($feed->{atom}->updated)  if $feed->{atom}->updated;
130         return undef;
131     }
132 }
133
134 sub entries {
135     my @entries;
136     for my $entry ($_[0]->{atom}->entries) {
137         push @entries, XML::Feed::Entry::Format::Atom->wrap($entry);
138     }
139
140     @entries;
141 }
142
143 sub add_entry {
144     my $feed  = shift;
145     my $entry = shift || return;
146     $entry    = $feed->_convert_entry($entry);
147     $feed->{atom}->add_entry($entry->unwrap);
148 }
149
150 sub as_xml { $_[0]->{atom}->as_xml }
151
152 package XML::Feed::Entry::Format::Atom;
153 use strict;
154
155 use base qw( XML::Feed::Entry );
156 use XML::Atom::Util qw( iso2dt );
157 use XML::Feed::Content;
158 use XML::Atom::Entry;
159 use List::Util qw( first );
160
161 sub init_empty {
162     my $entry = shift;
163     $entry->{entry} = XML::Atom::Entry->new(Version => 1.0);
164     1;
165 }
166
167 sub title { shift->{entry}->title(@_) }
168 sub source { shift->{entry}->source(@_) }
169 sub updated { shift->{entry}->updated(@_) }
170 sub base { shift->{entry}->base(@_) }
171
172 sub link {
173     my $entry = shift;
174     if (@_) {
175         $entry->{entry}->add_link({ rel => 'alternate', href => $_[0],
176                                     type => 'text/html', });
177     } else {
178         my $l = first { !defined $_->rel || $_->rel eq 'alternate' } $entry->{entry}->link;
179         $l ? $l->href : undef;
180     }
181 }
182
183 sub summary {
184     my $entry = shift;
185     if (@_) {
186                 my %param;
187                 if (ref($_[0]) eq 'XML::Feed::Content') {
188                         %param = (Body => $_[0]->body);
189                 } else {
190                          %param = (Body => $_[0]);
191                 }
192                 $entry->{entry}->summary(XML::Atom::Content->new(%param, Version => 1.0));
193     } else {
194                 my $s = $entry->{entry}->summary;
195         # map Atom types to MIME types
196         my $type = ($s && ref($s) eq 'XML::Feed::Content') ? $s->type : undef;
197         if ($type) {
198             $type = 'text/html'  if $type eq 'xhtml' || $type eq 'html';
199             $type = 'text/plain' if $type eq 'text';
200         }
201                 my $body = $s;  
202                 if (defined $s && ref($s) eq 'XML::Feed::Content') {
203                         $body = $s->body;
204                 }
205         XML::Feed::Content->wrap({ type => $type,
206                                    body => $body });
207     }
208 }
209
210 my %types = (
211         'text/xhtml' => 'xhtml',
212         'text/html'  => 'html',
213         'text/plain' => 'text',
214 );
215
216 sub content {
217     my $entry = shift;
218     if (@_) {
219         my %param;
220         my $base;
221         if (ref($_[0]) eq 'XML::Feed::Content') {
222                         if (defined $_[0]->type && defined $types{$_[0]->type}) {
223                     %param = (Body => $_[0]->body, Type => $types{$_[0]->type});
224                         } else {
225                     %param = (Body => $_[0]->body);
226                         }
227             $base = $_[0]->base if defined $_[0]->base;
228         } else {
229             %param = (Body => $_[0]);
230         }
231         $entry->{entry}->content(XML::Atom::Content->new(%param, Version => 1.0));
232         $entry->{entry}->content->base($base) if defined $base;
233     } else {
234         my $c = $entry->{entry}->content;
235
236         # map Atom types to MIME types
237         my $type = $c ? $c->type : undef;
238         if ($type) {
239             $type = 'text/html'  if $type eq 'xhtml' || $type eq 'html';
240             $type = 'text/plain' if $type eq 'text';
241         }
242
243         XML::Feed::Content->wrap({ type => $type,
244                                    base => $c ? $c->base : undef, 
245                                    body => $c ? $c->body : undef });
246     }
247 }
248
249 sub category {
250     my $entry = shift;
251     my $ns = XML::Atom::Namespace->new(dc => 'http://purl.org/dc/elements/1.1/');
252     if (@_) {
253         $entry->{entry}->add_category({ term => $_[0] });
254     } else {
255         my $category = $entry->{entry}->category;
256         my @return = $category ? ($category->label || $category->term) : $entry->{entry}->getlist($ns, 'subject');
257         return wantarray? @return : $return[0];
258     }
259 }
260
261 sub author {
262     my $entry = shift;
263     if (@_ && $_[0]) {
264         my $person = XML::Atom::Person->new(Version => 1.0);
265         $person->name($_[0]);
266         $entry->{entry}->author($person);
267     } else {
268         $entry->{entry}->author ? $entry->{entry}->author->name : undef;
269     }
270 }
271
272 sub id { shift->{entry}->id(@_) }
273
274 sub issued {
275     my $entry = shift;
276     if (@_) {
277         $entry->{entry}->issued(DateTime::Format::W3CDTF->format_datetime($_[0])) if $_[0];
278     } else {
279         $entry->{entry}->issued ? iso2dt($entry->{entry}->issued) : undef;
280     }
281 }
282
283 sub modified {
284     my $entry = shift;
285     if (@_) {
286         $entry->{entry}->modified(DateTime::Format::W3CDTF->format_datetime($_[0])) if $_[0];
287     } else {
288         return iso2dt($entry->{entry}->modified) if $entry->{entry}->modified;
289         return iso2dt($entry->{entry}->updated)  if $entry->{entry}->updated;
290         return undef;
291     }
292 }
293
294 sub lat {
295     my $entry = shift;
296     if (@_) {
297    $entry->{entry}->lat($_[0]) if $_[0];
298     } else {
299    $entry->{entry}->lat;
300     }
301 }
302
303 sub long {
304     my $entry = shift;
305     if (@_) {
306    $entry->{entry}->long($_[0]) if $_[0];
307     } else {
308    $entry->{entry}->long;
309     }
310 }
311
312 1;