]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/WWW/SuperCat/Feed.pm
MARC21 feed support
[working/Evergreen.git] / Open-ILS / src / perlmods / lib / 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 use DateTime;
10 use DateTime::Format::Mail;
11
12
13 sub exists {
14         my $class = shift;
15         my $type = shift;
16
17         return 1 if UNIVERSAL::can("OpenILS::WWW::SuperCat::Feed::$type" => 'new');
18         return 0;
19 }
20
21 sub new {
22         my $class = shift;
23         my $type = shift;
24         if ($type) {
25                 $class .= '::'.$type;
26                 return $class->new;
27         }
28         throw OpenSRF::EX::ERROR ("I need a feed type!") ;
29 }
30
31 sub build {
32         my $class = shift;
33         my $xml = shift;
34         return undef unless $xml;
35
36         $parser = new XML::LibXML if (!$parser);
37
38         my $self = { doc => $parser->parse_string($xml), items => [] };
39
40         $self = bless $self => $class;
41         $self->{count} = 0;
42         return $self;
43 }
44
45 sub type {
46         my $self = shift;
47         my $type = shift;
48         $self->{type} = $type if ($type);
49         return $self->{type};
50 }
51
52 sub count {
53         my $self = shift;
54         return $self->{count};
55 }
56
57 sub search {
58         my $self = shift;
59         my $search = shift;
60         $self->{search} = $search if ($search);
61         return $self->{search};
62 }
63
64 sub class {
65         my $self = shift;
66         my $search = shift;
67         $self->{class} = $search if ($search);
68         return $self->{class};
69 }
70
71 sub Sort {
72         my $self = shift;
73         my $search = shift;
74         $self->{sort} = $search if ($search);
75         return $self->{sort};
76 }
77
78 sub SortDir {
79         my $self = shift;
80         my $search = shift;
81         $self->{sort_dir} = $search if ($search);
82         return $self->{sort_dir};
83 }
84
85 sub lang {
86         my $self = shift;
87         my $search = shift;
88         $self->{lang} = $search if ($search);
89         return $self->{lang};
90 }
91
92 sub lib {
93         my $self = shift;
94         my $lib = shift;
95         $self->{lib} = $lib if ($lib);
96         return $self->{lib};
97 }
98
99 sub base {
100         my $self = shift;
101         my $base = shift;
102         $self->{base} = $base if ($base);
103         return $self->{base};
104 }
105
106 sub root {
107         my $self = shift;
108         my $root = shift;
109         $self->{root} = $root if ($root);
110         return $self->{root};
111 }
112
113 sub unapi {
114         my $self = shift;
115         my $unapi = shift;
116         $self->{unapi} = $unapi if ($unapi);
117         return $self->{unapi};
118 }
119
120 sub push_item {
121         my $self = shift;
122         $self->{count} += scalar(@_);
123         push @{ $self->{items} }, @_;
124 }
125
126 sub items {
127         my $self = shift;
128         return @{ $self->{items} } if (wantarray);
129         return $self->{items};
130 }
131
132 sub _add_node {
133         my $self = shift;
134
135         my $xpath = shift;
136         my $new = shift;
137
138         for my $node ($self->{doc}->findnodes($xpath)) {
139                 $node->appendChild($new);
140                 last;
141         }
142 }
143
144 sub _create_node {
145         my $self = shift;
146
147         my $xpath = shift;
148         my $ns = shift;
149         my $name = shift;
150         my $text = shift;
151         my $attrs = shift;
152
153         for my $node ($self->{doc}->findnodes($xpath)) {
154                 my $new = $self->{doc}->createElement($name) if (!$ns);
155                 $new = $self->{doc}->createElementNS($ns,$name) if ($ns);
156
157                 $new->appendChild( $self->{doc}->createTextNode( $text ) )
158                         if (defined $text);
159
160                 if (ref($attrs)) {
161                         for my $key (keys %$attrs) {
162                                 next unless $$attrs{$key};
163                                 $new->setAttribute( $key => $$attrs{$key} );
164                         }
165                 }
166
167                 $node->appendChild( $new );
168
169                 return $new;
170         }
171 }
172
173 sub add_item {
174         my $self = shift;
175         my $class = ref($self) || $self;
176         $class .= '::item';
177
178         my $item_xml = shift;
179         my $entry = $class->new($item_xml);
180         return undef unless $entry;
181
182         $entry->base($self->base);
183         $entry->unapi($self->unapi);
184
185         $self->push_item($entry);
186         return $entry;
187 }
188
189 sub add_holdings {
190         my $self = shift;
191         my $holdings_xml = shift;
192
193         return $self unless ($holdings_xml);
194
195         $parser = new XML::LibXML if (!$parser);
196         my $new_doc = $parser->parse_string($holdings_xml);
197
198         for my $root ( $self->{doc}->findnodes($self->{holdings_xpath}) ) {
199                 $root->appendChild($new_doc->documentElement);
200                 last;
201         }
202         return $self;
203 }
204
205 sub composeDoc {
206         my $self = shift;
207         for my $root ( $self->{doc}->findnodes($self->{item_xpath}) ) {
208                 for my $item ( $self->items ) {
209                         $root->appendChild( $item->{doc}->documentElement );
210                 }
211                 last;
212         }
213 }
214
215 sub toString {
216         my $self = shift;
217         $self->composeDoc;
218         return $self->{doc}->toString(1);
219 }
220
221 sub id {};
222 sub link {};
223 sub title {};
224 sub update_ts {};
225 sub creator {};
226 sub description {};
227
228 #----------------------------------------------------------
229
230 package OpenILS::WWW::SuperCat::Feed::atom;
231 use base 'OpenILS::WWW::SuperCat::Feed';
232 use OpenSRF::Utils qw/:datetime/;
233
234 sub new {
235         my $class = shift;
236         my $self = $class->SUPER::build('<feed xmlns:atom="http://www.w3.org/2005/Atom"/>');
237         $self->{doc}->documentElement->setNamespace('http://www.w3.org/2005/Atom', undef);
238         $self->{doc}->documentElement->setNamespace('http://www.w3.org/2005/Atom', 'atom');
239         $self->{type} = 'application/atom+xml';
240         $self->{item_xpath} = '/atom:feed';
241         return $self;
242 }
243
244 sub title {
245         my $self = shift;
246         my $text = shift;
247         $self->_create_node('/atom:feed','http://www.w3.org/2005/Atom','title', $text);
248 }
249
250 sub update_ts {
251         my $self = shift;
252         # ATOM demands RFC-3339 compliant datetime formats
253         my $text = shift || gmtime_ISO8601();
254         $self->_create_node($self->{item_xpath},'http://www.w3.org/2005/Atom','updated', $text);
255 }
256
257 sub creator {
258         my $self = shift;
259         my $text = shift;
260         $self->_create_node('/atom:feed','http://www.w3.org/2005/Atom','author');
261         $self->_create_node('/atom:feed/atom:author', 'http://www.w3.org/2005/Atom','name', $text);
262 }
263
264 sub link {
265         my $self = shift;
266         my $type = shift;
267         my $id = shift;
268         my $mime = shift || "application/x-$type+xml";
269         my $title = shift;
270
271         $type = 'self' if ($type eq 'atom');
272
273         $self->_create_node(
274                 $self->{item_xpath},
275                 'http://www.w3.org/2005/Atom',
276                 'link',
277                 undef,
278                 { rel => $type,
279                   href => $id,
280                   title => $title,
281                   type => $mime,
282                 }
283         );
284 }
285
286 sub id {
287         my $self = shift;
288         my $id = shift;
289
290         $self->_create_node( $self->{item_xpath}, 'http://www.w3.org/2005/Atom', 'id', $id );
291 }
292
293 package OpenILS::WWW::SuperCat::Feed::atom::item;
294 use base 'OpenILS::WWW::SuperCat::Feed::atom';
295
296 sub new {
297         my $class = shift;
298         my $xml = shift;
299         my $self = $class->SUPER::build($xml);
300         $self->{doc}->documentElement->setNamespace('http://www.w3.org/2005/Atom', undef);
301         $self->{doc}->documentElement->setNamespace('http://www.w3.org/2005/Atom', 'atom');
302         $self->{item_xpath} = '/atom:entry';
303         $self->{holdings_xpath} = '/atom:entry';
304         $self->{type} = 'application/atom+xml';
305         return $self;
306 }
307
308
309 #----------------------------------------------------------
310
311 package OpenILS::WWW::SuperCat::Feed::rss2;
312 use base 'OpenILS::WWW::SuperCat::Feed';
313
314 sub new {
315         my $class = shift;
316         my $self = $class->SUPER::build('<rss version="2.0"><channel/></rss>');
317         $self->{type} = 'application/rss+xml';
318         $self->{item_xpath} = '/rss/channel';
319         return $self;
320 }
321
322 sub title {
323         my $self = shift;
324         my $text = shift;
325         $self->_create_node('/rss/channel',undef,'title', $text);
326 }
327
328 sub description {
329         my $self = shift;
330         my $text = shift;
331         $self->_create_node('/rss/channel',undef,'description', $text);
332 }
333
334 sub update_ts {
335         my $self = shift;
336         # RSS2 demands RFC-822 compliant datetime formats
337         my $text = shift || DateTime::Format::Mail->format_datetime(DateTime->now());
338         $self->_create_node($self->{item_xpath},undef,'lastBuildDate', $text);
339 }
340
341 sub creator {
342         my $self = shift;
343         my $text = shift;
344         $self->_create_node('/rss/channel', undef,'generator', $text);
345 }
346
347 sub link {
348         my $self = shift;
349         my $type = shift;
350         my $id = shift;
351         my $mime = shift || "application/x-$type+xml";
352
353         if ($type eq 'rss2' or $type eq 'alternate') {
354                 # Just link to ourself using standard RSS2 link element
355                 $self->_create_node(
356                         $self->{item_xpath},
357                         undef,
358                         'link',
359                         $id,
360                         undef
361                 );
362         } else {
363                 # Alternate link: use XHTML link element
364                 $self->_create_node(
365                         $self->{item_xpath},
366                         'http://www.w3.org/1999/xhtml',
367                         'xhtml:link',
368                         $id,
369                         { rel => $type,
370                           type => $mime,
371                         }
372                 );
373         }
374 }
375
376 sub id {
377         my $self = shift;
378         my $id = shift;
379
380         $self->_create_node($self->{item_xpath}, undef,'guid', $id);
381 }
382
383 package OpenILS::WWW::SuperCat::Feed::rss2::item;
384 use base 'OpenILS::WWW::SuperCat::Feed::rss2';
385
386 sub new {
387         my $class = shift;
388         my $xml = shift;
389         my $self = $class->SUPER::build($xml);
390         $self->{type} = 'application/rss+xml';
391         $self->{item_xpath} = '/item';
392         $self->{holdings_xpath} = '/item';
393         return $self;
394 }
395
396 sub update_ts {
397         my $self = shift;
398         # RSS2 demands RFC-822 compliant datetime formats
399         my $text = shift;
400         if (!$text) {
401                 # No date passed in, default to now
402                 $text = DateTime::Format::Mail->format_datetime(DateTime->now());
403         } elsif ($text =~ m/^\s*(\d{4})\.?\s*$/o) {
404                 # Publication date is just a year, convert accordingly
405                 my $year = DateTime->new(year=>$1);
406                 $text = DateTime::Format::Mail->format_datetime($year);
407         }
408         $self->_create_node($self->{item_xpath},undef,'pubDate', $text);
409 }
410
411 sub id {
412         my $self = shift;
413         my $id = shift;
414
415         $self->_create_node(
416                 $self->{item_xpath},
417                 undef,
418                 'guid',
419                 $id,
420                 {
421                         isPermaLink=>"false"
422                 }
423         );
424 }
425
426 #----------------------------------------------------------
427
428 package OpenILS::WWW::SuperCat::Feed::mods;
429 use base 'OpenILS::WWW::SuperCat::Feed';
430
431 sub new {
432         my $class = shift;
433         my $self = $class->SUPER::build('<modsCollection version="3.0" xmlns="http://www.loc.gov/mods/" xmlns:mods="http://www.loc.gov/mods/"/>');
434         $self->{type} = 'application/xml';
435         $self->{item_xpath} = '/mods:modsCollection';
436         return $self;
437 }
438
439 package OpenILS::WWW::SuperCat::Feed::mods::item;
440 use base 'OpenILS::WWW::SuperCat::Feed::mods';
441
442 sub new {
443         my $class = shift;
444         my $xml = shift;
445         my $self = $class->SUPER::build($xml);
446         $self->{doc}->documentElement->setNamespace('http://www.loc.gov/mods/', 'mods');
447         $self->{doc}->documentElement->setNamespace('http://www.loc.gov/mods/', undef, 1);
448         $self->{type} = 'application/xml';
449         $self->{holdings_xpath} = '/mods:mods';
450         return $self;
451 }
452
453 my $linkid = 1;
454
455 sub link {
456         my $self = shift;
457         my $type = shift;
458         my $id = shift;
459
460         if ($type eq 'unapi' || $type eq 'opac') {
461                 $self->_create_node(
462                         'mods:mods',
463             undef,
464                         'relatedItem',
465                         undef,
466                         { type => 'otherFormat', id => 'link-'.$linkid }
467                 );
468                 $self->_create_node(
469                         "mods:mods/relatedItem[\@id='link-$linkid']",
470             undef,
471                         'recordIdentifier',
472                         $id
473                 );
474                 $linkid++;
475         }
476 }
477
478 #----------------------------------------------------------
479
480 package OpenILS::WWW::SuperCat::Feed::mods3;
481 use base 'OpenILS::WWW::SuperCat::Feed::mods';
482
483 sub new {
484         my $class = shift;
485         my $self = $class->SUPER::build('<modsCollection version="3.0" xmlns="http://www.loc.gov/mods/v3" xmlns:mods="http://www.loc.gov/mods/v3"/>');
486         $self->{type} = 'application/xml';
487         $self->{item_xpath} = '/mods:modsCollection';
488         return $self;
489 }
490
491 package OpenILS::WWW::SuperCat::Feed::mods3::item;
492 use base 'OpenILS::WWW::SuperCat::Feed::mods::item';
493
494 sub new {
495         my $class = shift;
496         my $xml = shift;
497         my $self = $class->SUPER::build($xml);
498         $self->{doc}->documentElement->setNamespace('http://www.loc.gov/mods/v3', 'mods');
499         $self->{doc}->documentElement->setNamespace('http://www.loc.gov/mods/v3', undef, 1);
500         $self->{type} = 'application/xml';
501         $self->{holdings_xpath} = '/mods:mods';
502         return $self;
503 }
504
505 sub link {
506         my $self = shift;
507         my $type = shift;
508         my $id = shift;
509
510         if ($type eq 'unapi' || $type eq 'opac') {
511                 $self->_create_node(
512                         'mods:mods',
513                         undef,
514                         'relatedItem',
515                         undef,
516                         { type => 'otherFormat', id => 'link-'.$linkid }
517                 );
518                 $self->_create_node(
519                         "mods:mods/relatedItem[\@id='link-$linkid']",
520                         undef,
521                         'recordIdentifier',
522                         $id
523                 );
524                 $linkid++;
525         }
526 }
527
528
529 #----------------------------------------------------------
530
531 package OpenILS::WWW::SuperCat::Feed::mods32;
532 use base 'OpenILS::WWW::SuperCat::Feed::mods3';
533
534 sub new {
535         my $class = shift;
536         my $self = $class->SUPER::build('<modsCollection version="3.2" xmlns="http://www.loc.gov/mods/v3" xmlns:mods="http://www.loc.gov/mods/v3"/>');
537         $self->{type} = 'application/xml';
538         $self->{item_xpath} = '/mods:modsCollection';
539         return $self;
540 }
541
542 package OpenILS::WWW::SuperCat::Feed::mods32::item;
543 use base 'OpenILS::WWW::SuperCat::Feed::mods3::item';
544
545 #----------------------------------------------------------
546
547 package OpenILS::WWW::SuperCat::Feed::mods33;
548 use base 'OpenILS::WWW::SuperCat::Feed::mods3';
549
550 sub new {
551         my $class = shift;
552         my $self = $class->SUPER::build('<modsCollection version="3.3" xmlns="http://www.loc.gov/mods/v3" xmlns:mods="http://www.loc.gov/mods/v3"/>');
553         $self->{type} = 'application/xml';
554         $self->{item_xpath} = '/mods:modsCollection';
555         return $self;
556 }
557
558 package OpenILS::WWW::SuperCat::Feed::mods33::item;
559 use base 'OpenILS::WWW::SuperCat::Feed::mods3::item';
560
561
562 #----------------------------------------------------------
563
564 package OpenILS::WWW::SuperCat::Feed::marcxml;
565 use base 'OpenILS::WWW::SuperCat::Feed';
566
567 sub new {
568         my $class = shift;
569         my $self = $class->SUPER::build('<collection xmlns="http://www.loc.gov/MARC21/slim" xmlns:marc="http://www.loc.gov/MARC21/slim"/>');
570         $self->{type} = 'application/xml';
571         $self->{item_xpath} = '/marc:collection';
572         return $self;
573 }
574 sub link {
575         my $self = shift;
576         my $type = shift;
577         my $id = shift;
578
579         if ($type eq 'unapi') {
580                 $self->_create_node(
581                         'marc:collection',
582                         'http://www.w3.org/1999/xhtml',
583                         'xhtml:link',
584                         undef,
585                         { rel => 'unapi-server', href => $id, title => "unapi" }
586                 );
587                 $linkid++;
588         }
589 }
590
591
592 package OpenILS::WWW::SuperCat::Feed::marcxml::item;
593 use base 'OpenILS::WWW::SuperCat::Feed::marcxml';
594
595 sub new {
596         my $class = shift;
597         my $xml = shift;
598         my $self = $class->SUPER::build($xml);
599         return undef unless $self;
600         $self->{doc}->documentElement->setNamespace('http://www.loc.gov/MARC21/slim', undef);
601         $self->{type} = 'application/xml';
602         $self->{holdings_xpath} = '/*[local-name()="record"]';
603         return $self;
604 }
605
606 sub link {
607         my $self = shift;
608         my $type = shift;
609         my $id = shift;
610
611         if ($type eq 'opac') {
612                 $self->_create_node(
613                         '*[local-name()="record"]',
614                         'http://www.w3.org/1999/xhtml',
615                         'xhtml:link',
616                         undef,
617                         { rel => 'otherFormat', href => $id, title => "Dynamic Details" }
618                 );
619                 $linkid++;
620         } elsif ($type eq 'unapi-id') {
621                 $self->_create_node(
622                         '*[local-name()="record"]',
623                         'http://www.w3.org/1999/xhtml',
624                         'xhtml:abbr',
625                         undef,
626                         {  title => $id, class => "unapi-id" }
627                 );
628                 $linkid++;
629         }
630 }
631
632
633 #----------------------------------------------------------
634
635 package OpenILS::WWW::SuperCat::Feed::html;
636 use base 'OpenILS::WWW::SuperCat::Feed::atom';
637
638 sub new {
639         my $class = shift;
640         my $self = $class->SUPER::new;
641         $self->type('text/html');
642         return $self;
643 }
644
645 our ($_parser, $_xslt, $xslt_file);
646
647 sub toString {
648         my $self = shift;
649         my $base = $self->base || '';
650         my $root = $self->root || '';
651         my $search = $self->search || '';
652         my $class = $self->class || '';
653         my $lib = $self->lib || '-';
654
655         $self->composeDoc;
656
657         $_parser ||= new XML::LibXML;
658         $_xslt ||= new XML::LibXSLT;
659
660         $xslt_file ||=
661                 OpenSRF::Utils::SettingsClient
662                         ->new
663                         ->config_value( dirs => 'xsl' ).
664                 "/ATOM2XHTML.xsl";
665
666         # parse the MODS xslt ...
667         my $atom2html_xslt = $_xslt->parse_stylesheet( $_parser->parse_file($xslt_file) );
668
669         my $new_doc = $atom2html_xslt->transform(
670                 $self->{doc},
671                 base_dir => "'$root'",
672                 lib => "'$lib'",
673                 searchTerms => "'$search'",
674                 searchClass => "'$class'",
675         );
676
677         return $new_doc->toString(1); 
678 }
679
680
681 package OpenILS::WWW::SuperCat::Feed::html::item;
682 use base 'OpenILS::WWW::SuperCat::Feed::atom::item';
683
684 #----------------------------------------------------------
685
686 package OpenILS::WWW::SuperCat::Feed::htmlcard;
687 use base 'OpenILS::WWW::SuperCat::Feed::marcxml';
688
689 sub new {
690         my $class = shift;
691         my $self = $class->SUPER::new;
692         $self->type('text/html');
693         $self->{xsl} = "/MARC21slim2HTMLCard.xsl";
694         return $self;
695 }
696
697 our ($_parser, $_xslt, $xslt_file);
698
699 sub toString {
700         my $self = shift;
701         my $base = $self->base || '';
702         my $root = $self->root || '';
703         my $search = $self->search || '';
704         my $sort = $self->Sort || '';
705         my $sort_dir = $self->SortDir || '';
706         my $lang = $self->lang || '';
707         my $lib = $self->lib || '-';
708
709         $self->composeDoc;
710
711         $_parser ||= new XML::LibXML;
712         $_xslt ||= new XML::LibXSLT;
713
714         $xslt_file =
715                 OpenSRF::Utils::SettingsClient
716                         ->new
717                         ->config_value( dirs => 'xsl' ).$self->{xsl};
718
719         # parse the MODS xslt ...
720         my $atom2html_xslt = $_xslt->parse_stylesheet( $_parser->parse_file($xslt_file) );
721
722         my $new_doc = $atom2html_xslt->transform(
723                 $self->{doc},
724                 base_dir => "'$root'",
725                 lib => "'$lib'",
726                 searchTerms => "'$search'",
727                 searchSort => "'$sort'",
728                 searchSortDir => "'$sort_dir'",
729                 searchLang => "'$lang'",
730         );
731
732         return $new_doc->toString(1); 
733 }
734
735 package OpenILS::WWW::SuperCat::Feed::htmlcard::item;
736 use base 'OpenILS::WWW::SuperCat::Feed::marcxml::item';
737
738 package OpenILS::WWW::SuperCat::Feed::htmlholdings;
739 use base 'OpenILS::WWW::SuperCat::Feed::htmlcard';
740
741 sub new {
742         my $class = shift;
743         my $self = $class->SUPER::new;
744         $self->{xsl} = "/MARC21slim2HTMLCard-holdings.xsl";
745         return $self;
746 }
747
748 package OpenILS::WWW::SuperCat::Feed::htmlholdings::item;
749 use base 'OpenILS::WWW::SuperCat::Feed::htmlcard::item';
750
751
752 package OpenILS::WWW::SuperCat::Feed::marctxt;
753 use base 'OpenILS::WWW::SuperCat::Feed::marcxml';
754
755 sub new {
756         my $class = shift;
757         my $self = $class->SUPER::new;
758         $self->{type} = 'text/plain';
759         $self->{xsl} = "/MARC21slim2MARCtxt.xsl";
760         return $self;
761 }
762
763
764 our ($_parser, $_xslt, $xslt_file);
765
766 sub toString {
767         my $self = shift;
768         my $base = $self->base || '';
769         my $root = $self->root || '';
770         my $search = $self->search || '';
771         my $class = $self->class || '';
772         my $lib = $self->lib || '-';
773
774         $self->composeDoc;
775
776         $_parser ||= new XML::LibXML;
777         $_xslt ||= new XML::LibXSLT;
778
779         $xslt_file ||=
780                 OpenSRF::Utils::SettingsClient
781                         ->new
782                         ->config_value( dirs => 'xsl' ).
783                 $self->{xsl};
784
785         # parse the MARC text xslt ...
786         my $marctxt_xslt = $_xslt->parse_stylesheet( $_parser->parse_file($xslt_file) );
787
788         my $new_doc = $marctxt_xslt->transform(
789                 $self->{doc},
790                 base_dir => "'$root'",
791                 lib => "'$lib'",
792                 searchTerms => "'$search'",
793                 searchClass => "'$class'",
794         );
795
796         return $marctxt_xslt->output_string($new_doc); 
797 }
798
799
800 package OpenILS::WWW::SuperCat::Feed::marctxt::item;
801 use base 'OpenILS::WWW::SuperCat::Feed::marcxml::item';
802
803
804 package OpenILS::WWW::SuperCat::Feed::ris;
805 use base 'OpenILS::WWW::SuperCat::Feed::marcxml';
806
807 sub new {
808         my $class = shift;
809         my $self = $class->SUPER::new;
810         $self->{type} = 'text/plain';
811         $self->{xsl} = "/MARC21slim2RIS.xsl";
812         return $self;
813 }
814
815
816 our ($_parser, $_xslt, $xslt_file);
817
818 sub toString {
819         my $self = shift;
820         my $base = $self->base || '';
821         my $root = $self->root || '';
822         my $search = $self->search || '';
823         my $class = $self->class || '';
824         my $lib = $self->lib || '-';
825
826         $self->composeDoc;
827
828         $_parser ||= new XML::LibXML;
829         $_xslt ||= new XML::LibXSLT;
830
831         $xslt_file ||=
832                 OpenSRF::Utils::SettingsClient
833                         ->new
834                         ->config_value( dirs => 'xsl' ).
835                 $self->{xsl};
836
837         # parse the MARC text xslt ...
838         my $ris_xslt = $_xslt->parse_stylesheet( $_parser->parse_file($xslt_file) );
839
840         my $new_doc = $ris_xslt->transform(
841                 $self->{doc},
842                 base_dir => "'$root'",
843                 lib => "'$lib'",
844                 searchTerms => "'$search'",
845                 searchClass => "'$class'",
846         );
847
848         return $ris_xslt->output_string($new_doc); 
849 }
850
851
852 package OpenILS::WWW::SuperCat::Feed::ris::item;
853 use base 'OpenILS::WWW::SuperCat::Feed::marcxml::item';
854
855 package OpenILS::WWW::SuperCat::Feed::marc21;
856 use base 'OpenILS::WWW::SuperCat::Feed::marcxml';
857 use MARC::File::XML ( BinaryEncoding => 'utf8', RecordFormat => 'USMARC' );
858
859 sub new {
860         my $class = shift;
861         my $self = $class->SUPER::new;
862         $self->{type} = 'application/octet-stream';
863         return $self;
864 }
865
866
867 sub toString {
868     my $self = shift;
869
870     $self->{doc} = '';
871     for my $item ( $self->items ) {
872         my $r = MARC::Record->new_from_xml( $item->{doc}->toString(1) );
873         $self->{doc} .= $r->as_usmarc;
874     }
875
876     utf8::encode($self->{doc});
877     return $self->{doc};
878 }
879
880 package OpenILS::WWW::SuperCat::Feed::marc21::item;
881 use base 'OpenILS::WWW::SuperCat::Feed::marcxml::item';
882
883
884 1;