]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/WWW/SuperCat/Feed.pm
improving the dumpac
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / WWW / SuperCat / Feed.pm
1 package OpenILS::WWW::SuperCat::Feed;
2 use strict; use warnings;
3 use vars qw/$parser/;
4 use OpenSRF::EX qw(:try);
5 use XML::LibXML;
6 use XML::LibXSLT;
7 use OpenSRF::Utils::SettingsClient;
8 use CGI;
9
10 sub new {
11         my $class = shift;
12         my $type = shift;
13         if ($type) {
14                 $class .= '::'.$type;
15                 return $class->new;
16         }
17         throw OpenSRF::EX::ERROR ("I need a feed type!") ;
18 }
19
20 sub build {
21         my $class = shift;
22         my $xml = shift;
23
24         $parser = new XML::LibXML if (!$parser);
25
26         my $self = { doc => $parser->parse_string($xml), items => [] };
27
28         return bless $self => $class;
29 }
30
31 sub type {
32         my $self = shift;
33         my $type = shift;
34         $self->{type} = $type if ($type);
35         return $self->{type};
36 }
37
38 sub search {
39         my $self = shift;
40         my $search = shift;
41         $self->{search} = $search if ($search);
42         return $self->{search};
43 }
44
45 sub class {
46         my $self = shift;
47         my $search = shift;
48         $self->{class} = $search if ($search);
49         return $self->{class};
50 }
51
52 sub lib {
53         my $self = shift;
54         my $lib = shift;
55         $self->{lib} = $lib if ($lib);
56         return $self->{lib};
57 }
58
59 sub base {
60         my $self = shift;
61         my $base = shift;
62         $self->{base} = $base if ($base);
63         return $self->{base};
64 }
65
66 sub root {
67         my $self = shift;
68         my $root = shift;
69         $self->{root} = $root if ($root);
70         return $self->{root};
71 }
72
73 sub unapi {
74         my $self = shift;
75         my $unapi = shift;
76         $self->{unapi} = $unapi if ($unapi);
77         return $self->{unapi};
78 }
79
80 sub push_item {
81         my $self = shift;
82         push @{ $self->{items} }, @_;
83 }
84
85 sub items {
86         my $self = shift;
87         return @{ $self->{items} } if (wantarray);
88         return $self->{items};
89 }
90
91 sub _add_node {
92         my $self = shift;
93
94         my $xpath = shift;
95         my $new = shift;
96
97         for my $node ($self->{doc}->findnodes($xpath)) {
98                 $node->appendChild($new);
99                 last;
100         }
101 }
102
103 sub _create_node {
104         my $self = shift;
105
106         my $xpath = shift;
107         my $ns = shift;
108         my $name = shift;
109         my $text = shift;
110         my $attrs = shift;
111
112         for my $node ($self->{doc}->findnodes($xpath)) {
113                 my $new = $self->{doc}->createElement($name) if (!$ns);
114                 $new = $self->{doc}->createElementNS($ns,$name) if ($ns);
115
116                 $new->appendChild( $self->{doc}->createTextNode( $text ) )
117                         if (defined $text);
118
119                 if (ref($attrs)) {
120                         for my $key (keys %$attrs) {
121                                 $new->setAttribute( $key => $$attrs{$key} );
122                         }
123                 }
124
125                 $node->appendChild( $new );
126
127                 return $new;
128         }
129 }
130
131 sub add_item {
132         my $self = shift;
133         my $class = ref($self) || $self;
134         $class .= '::item';
135
136         my $item_xml = shift;
137         my $entry = $class->new($item_xml);
138
139         $entry->base($self->base);
140         $entry->unapi($self->unapi);
141
142         $self->push_item($entry);
143         return $entry;
144 }
145
146 sub add_holdings {
147         my $self = shift;
148         my $holdings_xml = shift;
149
150         $parser = new XML::LibXML if (!$parser);
151         my $new_doc = $parser->parse_string($holdings_xml);
152
153         for my $root ( $self->{doc}->findnodes($self->{holdings_xpath}) ) {
154                 $root->appendChild($new_doc->documentElement);
155                 last;
156         }
157         return $self;
158 }
159
160 sub composeDoc {
161         my $self = shift;
162         for my $root ( $self->{doc}->findnodes($self->{item_xpath}) ) {
163                 for my $item ( $self->items ) {
164                         $root->appendChild( $item->{doc}->documentElement );
165                 }
166                 last;
167         }
168 }
169
170 sub toString {
171         my $self = shift;
172         $self->composeDoc;
173         return $self->{doc}->toString(1);
174 }
175
176 sub id {};
177 sub link {};
178 sub title {};
179 sub update_ts {};
180 sub creator {};
181
182 #----------------------------------------------------------
183
184 package OpenILS::WWW::SuperCat::Feed::atom;
185 use base 'OpenILS::WWW::SuperCat::Feed';
186
187 sub new {
188         my $class = shift;
189         my $self = $class->SUPER::build('<atom:feed xmlns:atom="http://www.w3.org/2005/Atom"/>');
190         $self->{type} = 'application/xml';
191         $self->{item_xpath} = '/atom:feed';
192         return $self;
193 }
194
195 sub title {
196         my $self = shift;
197         my $text = shift;
198         $self->_create_node('/atom:feed','http://www.w3.org/2005/Atom','atom:title', $text);
199 }
200
201 sub update_ts {
202         my $self = shift;
203         my $text = shift;
204         $self->_create_node('/atom:feed','http://www.w3.org/2005/Atom','atom:updated', $text);
205 }
206
207 sub creator {
208         my $self = shift;
209         my $text = shift;
210         $self->_create_node('/atom:feed','http://www.w3.org/2005/Atom','atom:author');
211         $self->_create_node('/atom:feed/atom:author', 'http://www.w3.org/2005/Atom','atom:name', $text);
212 }
213
214 sub link {
215         my $self = shift;
216         my $type = shift;
217         my $id = shift;
218         my $mime = shift || "application/x-$type+xml";
219         my $title = shift;
220
221         $type = 'self' if ($type eq 'atom');
222
223         $self->_create_node(
224                 $self->{item_xpath},
225                 'http://www.w3.org/2005/Atom',
226                 'atom:link',
227                 undef,
228                 { rel => $type,
229                   href => $id,
230                   title => $title,
231                   type => $mime,
232                 }
233         );
234 }
235
236 sub id {
237         my $self = shift;
238         my $id = shift;
239
240         $self->_create_node( '/atom:feed', 'http://www.w3.org/2005/Atom', 'atom:id', $id );
241 }
242
243 package OpenILS::WWW::SuperCat::Feed::atom::item;
244 use base 'OpenILS::WWW::SuperCat::Feed::atom';
245
246 sub new {
247         my $class = shift;
248         my $xml = shift;
249         my $self = $class->SUPER::build($xml);
250         $self->{doc}->documentElement->setNamespace('http://www.w3.org/2005/Atom', 'atom');
251         $self->{item_xpath} = '/atom:entry';
252         $self->{holdings_xpath} = '/atom:entry';
253         $self->{type} = 'application/xml';
254         return $self;
255 }
256
257
258 #----------------------------------------------------------
259
260 package OpenILS::WWW::SuperCat::Feed::rss2;
261 use base 'OpenILS::WWW::SuperCat::Feed';
262
263 sub new {
264         my $class = shift;
265         my $self = $class->SUPER::build('<rss version="2.0"><channel/></rss>');
266         $self->{type} = 'application/xml';
267         $self->{item_xpath} = '/rss/channel';
268         return $self;
269 }
270
271 sub title {
272         my $self = shift;
273         my $text = shift;
274         $self->_create_node('/rss/channel',undef,'title', $text);
275 }
276
277 sub update_ts {
278         my $self = shift;
279         my $text = shift;
280         $self->_create_node('/rss/channel',undef,'lastBuildDate', $text);
281 }
282
283 sub creator {
284         my $self = shift;
285         my $text = shift;
286         $self->_create_node('/rss/channel', undef,'generator', $text);
287 }
288
289 sub link {
290         my $self = shift;
291         my $type = shift;
292         my $id = shift;
293         my $mime = shift || "application/x-$type+xml";
294
295         $type = 'self' if ($type eq 'rss2');
296
297         $self->_create_node(
298                 $self->{item_xpath},
299                 undef,
300                 'link',
301                 $id,
302                 { rel => $type,
303                   type => $mime,
304                 }
305         );
306 }
307
308 package OpenILS::WWW::SuperCat::Feed::rss2::item;
309 use base 'OpenILS::WWW::SuperCat::Feed::rss2';
310
311 sub new {
312         my $class = shift;
313         my $xml = shift;
314         my $self = $class->SUPER::build($xml);
315         $self->{type} = 'application/xml';
316         $self->{item_xpath} = '/item';
317         $self->{holdings_xpath} = '/item';
318         return $self;
319 }
320
321
322 #----------------------------------------------------------
323
324 package OpenILS::WWW::SuperCat::Feed::mods;
325 use base 'OpenILS::WWW::SuperCat::Feed';
326
327 sub new {
328         my $class = shift;
329         my $self = $class->SUPER::build('<mods:modsCollection version="3.0" xmlns:mods="http://www.loc.gov/mods/"/>');
330         $self->{type} = 'application/xml';
331         $self->{item_xpath} = '/mods:modsCollection';
332         return $self;
333 }
334
335 package OpenILS::WWW::SuperCat::Feed::mods::item;
336 use base 'OpenILS::WWW::SuperCat::Feed::mods';
337
338 sub new {
339         my $class = shift;
340         my $xml = shift;
341         my $self = $class->SUPER::build($xml);
342         $self->{doc}->documentElement->setNamespace('http://www.loc.gov/mods/', 'mods');
343         $self->{type} = 'application/xml';
344         $self->{holdings_xpath} = '/mods:mods';
345         return $self;
346 }
347
348 my $linkid = 1;
349
350 sub link {
351         my $self = shift;
352         my $type = shift;
353         my $id = shift;
354
355         if ($type eq 'unapi' || $type eq 'opac') {
356                 $self->_create_node(
357                         'mods:mods',
358                         'http://www.loc.gov/mods/',
359                         'mods:relatedItem',
360                         undef,
361                         { type => 'otherFormat', id => 'link-'.$linkid }
362                 );
363                 $self->_create_node(
364                         "mods:mods/mods:relatedItem[\@id='link-$linkid']",
365                         'http://www.loc.gov/mods/',
366                         'mods:recordIdentifier',
367                         $id
368                 );
369                 $linkid++;
370         }
371 }
372
373
374 #----------------------------------------------------------
375
376 package OpenILS::WWW::SuperCat::Feed::mods3;
377 use base 'OpenILS::WWW::SuperCat::Feed';
378
379 sub new {
380         my $class = shift;
381         my $self = $class->SUPER::build('<mods:modsCollection version="3.0" xmlns:mods="http://www.loc.gov/mods/v3"/>');
382         $self->{type} = 'application/xml';
383         $self->{item_xpath} = '/mods:modsCollection';
384         return $self;
385 }
386
387 package OpenILS::WWW::SuperCat::Feed::mods3::item;
388 use base 'OpenILS::WWW::SuperCat::Feed::mods3';
389
390 sub new {
391         my $class = shift;
392         my $xml = shift;
393         my $self = $class->SUPER::build($xml);
394         $self->{doc}->documentElement->setNamespace('http://www.loc.gov/mods/v3', 'mods');
395         $self->{type} = 'application/xml';
396         $self->{holdings_xpath} = '/mods:mods';
397         return $self;
398 }
399
400
401 #----------------------------------------------------------
402
403 package OpenILS::WWW::SuperCat::Feed::marcxml;
404 use base 'OpenILS::WWW::SuperCat::Feed';
405
406 sub new {
407         my $class = shift;
408         my $self = $class->SUPER::build('<marc:collection xmlns:marc="http://www.loc.gov/MARC21/slim"/>');
409         $self->{type} = 'application/xml';
410         $self->{item_xpath} = '/marc:collection';
411         return $self;
412 }
413
414 package OpenILS::WWW::SuperCat::Feed::marcxml::item;
415 use base 'OpenILS::WWW::SuperCat::Feed::marcxml';
416
417 sub new {
418         my $class = shift;
419         my $xml = shift;
420         my $self = $class->SUPER::build($xml);
421         $self->{doc}->documentElement->setNamespace('http://www.loc.gov/MARC21/slim', 'marc');
422         $self->{type} = 'application/xml';
423         $self->{holdings_xpath} = '/marc:record';
424         return $self;
425 }
426
427 #----------------------------------------------------------
428
429 package OpenILS::WWW::SuperCat::Feed::html;
430 use base 'OpenILS::WWW::SuperCat::Feed::atom';
431
432 sub new {
433         my $class = shift;
434         my $self = $class->SUPER::new;
435         $self->type('text/html');
436         return $self;
437 }
438
439 our ($_parser, $_xslt, $xslt_file);
440
441 sub toString {
442         my $self = shift;
443         my $base = $self->base || '';
444         my $root = $self->root || '';
445         my $search = $self->search || '';
446         my $class = $self->class || '';
447         my $lib = $self->lib || '-';
448
449         $self->composeDoc;
450
451         $_parser ||= new XML::LibXML;
452         $_xslt ||= new XML::LibXSLT;
453
454         $xslt_file ||=
455                 OpenSRF::Utils::SettingsClient
456                         ->new
457                         ->config_value( dirs => 'xsl' ).
458                 "/ATOM2XHTML.xsl";
459
460         # parse the MODS xslt ...
461         my $atom2html_xslt = $_xslt->parse_stylesheet( $_parser->parse_file($xslt_file) );
462
463         my $new_doc = $atom2html_xslt->transform(
464                 $self->{doc},
465                 base_dir => "'$root'",
466                 lib => "'$lib'",
467                 searchTerms => "'$search'",
468                 searchClass => "'$class'",
469         );
470
471         return $new_doc->toString(1); 
472 }
473
474
475 package OpenILS::WWW::SuperCat::Feed::html::item;
476 use base 'OpenILS::WWW::SuperCat::Feed::atom::item';
477
478 #----------------------------------------------------------
479
480 package OpenILS::WWW::SuperCat::Feed::htmlcard;
481 use base 'OpenILS::WWW::SuperCat::Feed::marcxml';
482
483 sub new {
484         my $class = shift;
485         my $self = $class->SUPER::new;
486         $self->type('text/html');
487         $self->{xsl} = "/MARC21slim2HTMLCard.xsl";
488         return $self;
489 }
490
491 our ($_parser, $_xslt, $xslt_file);
492
493 sub toString {
494         my $self = shift;
495         my $base = $self->base || '';
496         my $root = $self->root || '';
497         my $search = $self->search || '';
498         my $lib = $self->lib || '-';
499
500         $self->composeDoc;
501
502         $_parser ||= new XML::LibXML;
503         $_xslt ||= new XML::LibXSLT;
504
505         $xslt_file ||=
506                 OpenSRF::Utils::SettingsClient
507                         ->new
508                         ->config_value( dirs => 'xsl' ).$self->{xsl};
509
510         # parse the MODS xslt ...
511         my $atom2html_xslt = $_xslt->parse_stylesheet( $_parser->parse_file($xslt_file) );
512
513         my $new_doc = $atom2html_xslt->transform(
514                 $self->{doc},
515                 base_dir => "'$root'",
516                 lib => "'$lib'",
517                 searchTerms => "'$search'",
518         );
519
520         return $new_doc->toString(1); 
521 }
522
523 package OpenILS::WWW::SuperCat::Feed::htmlholdings;
524 use base 'OpenILS::WWW::SuperCat::Feed::htmlcard';
525
526 sub new {
527         my $class = shift;
528         my $self = $class->SUPER::new;
529         $self->{xsl} = "/MARC21slim2HTMLCard-holdings.xsl";
530         return $self;
531 }
532
533 package OpenILS::WWW::SuperCat::Feed::htmlcard::item;
534 use base 'OpenILS::WWW::SuperCat::Feed::marcxml::item';
535
536 package OpenILS::WWW::SuperCat::Feed::htmlholdings::item;
537 use base 'OpenILS::WWW::SuperCat::Feed::htmlcard::item';
538
539 1;