adding atom format support and bookbag feeds (atom/rss2/mods/html(soon))
authormiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 6 Mar 2006 05:50:43 +0000 (05:50 +0000)
committermiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 6 Mar 2006 05:50:43 +0000 (05:50 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@3264 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/perlmods/OpenILS/Application/SuperCat.pm
Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm

index 61ba2f4..1d00204 100644 (file)
@@ -63,6 +63,18 @@ sub child_init {
 
        $logger->debug("Got here!");
 
+       # parse the ATOM entry xslt ...
+       my $atom_xslt = $_parser->parse_file(
+               OpenSRF::Utils::SettingsClient
+                       ->new
+                       ->config_value( dirs => 'xsl' ).
+               "/MARC21slim2ATOM.xsl"
+       );
+       # and stash a transformer
+       $record_xslt{atom}{xslt} = $_xslt->parse_stylesheet( $atom_xslt );
+       $record_xslt{atom}{namespace_uri} = 'http://www.w3.org/2005/Atom';
+       $record_xslt{atom}{docs} = 'http://www.ietf.org/rfc/rfc4287.txt';
+
        # parse the RDFDC xslt ...
        my $rdf_dc_xslt = $_parser->parse_file(
                OpenSRF::Utils::SettingsClient
index 9c7dffa..da97a97 100644 (file)
@@ -12,15 +12,17 @@ use CGI;
 use Data::Dumper;
 
 use OpenSRF::EX qw(:try);
+use OpenSRF::Utils qw/:datetime/;
 use OpenSRF::System;
 use OpenSRF::AppSession;
 use XML::LibXML;
 
+use Unicode::Normalize;
 use OpenILS::Utils::Fieldmapper;
 
 
 # set the bootstrap config when this module is loaded
-my ($bootstrap, $supercat);
+my ($bootstrap, $supercat, $actor, $parser);
 
 sub import {
        my $self = shift;
@@ -31,6 +33,8 @@ sub import {
 sub child_init {
        OpenSRF::System->bootstrap_client( config_file => $bootstrap );
        $supercat = OpenSRF::AppSession->create('open-ils.supercat');
+       $actor = OpenSRF::AppSession->create('open-ils.actor');
+       $parser = new XML::LibXML;
 }
 
 sub oisbn {
@@ -271,4 +275,419 @@ sub supercat {
        return Apache2::Const::OK;
 }
 
+
+sub bookbag_feed {
+       my $apache = shift;
+       return Apache2::Const::DECLINED if (-e $apache->filename);
+
+       print "Content-type: application/xml; charset=utf-8\n\n";
+
+       my $cgi = new CGI;
+       (my $unapi = $cgi->url) =~ s{[^/]+/?$}{unapi};
+
+       my $year = (gmtime())[5];
+
+       my $host = $cgi->virtual_host || $cgi->server_name;
+       my $path = $apache->path_info;
+
+       my ($id,$type) = reverse split '/', $path;
+
+       my $bucket = $actor->request("open-ils.actor.container.public.flesh", 'biblio', $id)->gather(1);
+       my $bucket_tag = "tag:$host,$year:record_bucket/$id";
+
+       my $feed = create_record_feed(
+               $type,
+               [ map { $_->target_biblio_record_entry } @{ $bucket->items } ],
+               $unapi,
+       );
+
+       $feed->title("Items in Book Bag #".$bucket->id);
+       $feed->creator($host);
+       $feed->update_ts(gmtime_ISO8601());
+
+       $feed->link(atom => $id);
+       $feed->link(rss2 => $id);
+       $feed->link(html => $id);
+
+       print entityize($feed->toString) . "\n";
+
+       return Apache2::Const::OK;
+}
+
+sub create_record_feed {
+       my $type = shift;
+       my $records = shift;
+       my $unapi = shift;
+
+       my $cgi = new CGI;
+       my $base = $cgi->url;
+       my $host = $cgi->virtual_host || $cgi->server_name;
+
+       my $year = (gmtime())[5];
+
+       my $feed = new OpenILS::WWW::SuperCat::Feed ($type);
+       $feed->base($base);
+       $feed->unapi($unapi);
+
+       for my $rec (@$records) {
+               my $item_tag = "tag:$host,$year:biblio-record_entry/" . $rec;
+
+               my $xml = $supercat->request(
+                       "open-ils.supercat.record.$type.retrieve",
+                       $rec
+               )->gather(1);
+
+               my $node = $feed->add_item($xml);
+
+               $node->id($item_tag);
+               $node->link(unapi => $item_tag);
+       }
+
+       return $feed;
+}
+
+sub entityize {
+       my $stuff = NFC(shift());
+       $stuff =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
+       return $stuff;
+}
+
+package OpenILS::WWW::SuperCat::Feed;
+
+sub new {
+       my $class = shift;
+       my $type = shift;
+       if ($type) {
+               $class .= '::'.$type;
+               return $class->new;
+       }
+       throw OpenSRF::EX::ERROR ("I need a feed type!") ;
+}
+
+sub build {
+       my $class = shift;
+       my $xml = shift;
+
+       my $self = { doc => $parser->parse_string($xml), items => [] };
+
+       return bless $self => $class;
+}
+
+sub base {
+       my $self = shift;
+       my $base = shift;
+       $self->{base} = $base if ($base);
+       return $self->{base};
+}
+
+sub unapi {
+       my $self = shift;
+       my $unapi = shift;
+       $self->{unapi} = $unapi if ($unapi);
+       return $self->{unapi};
+}
+
+sub push_item {
+       my $self = shift;
+       push @{ $self->{items} }, @_;
+}
+
+sub items {
+       my $self = shift;
+       return @{ $self->{items} } if (wantarray);
+       return $self->{items};
+}
+
+sub _add_node {
+       my $self = shift;
+
+       my $xpath = shift;
+       my $new = shift;
+
+       for my $node ($self->{doc}->findnodes($xpath)) {
+               $node->appendChild($new);
+               last;
+       }
+}
+
+sub _create_node {
+       my $self = shift;
+
+       my $xpath = shift;
+       my $ns = shift;
+       my $name = shift;
+       my $text = shift;
+       my $attrs = shift;
+
+       for my $node ($self->{doc}->findnodes($xpath)) {
+               my $new = $self->{doc}->createElement($name) if (!$ns);
+               $new = $self->{doc}->createElementNS($ns,$name) if ($ns);
+
+               $new->appendChild( $self->{doc}->createTextNode( $text ) )
+                       if ($text);
+
+               if (ref($attrs)) {
+                       for my $key (keys %$attrs) {
+                               $new->setAttribute( $key => $$attrs{$key} );
+                       }
+               }
+
+               $node->appendChild( $new );
+
+               return $new;
+       }
+}
+
+sub add_item {
+       my $self = shift;
+       my $class = ref($self) || $self;
+       $class .= '::item';
+
+       my $item_xml = shift;
+       my $entry = $class->new($item_xml);
+
+       $entry->base($self->base);
+       $entry->unapi($self->unapi);
+
+       $self->push_item($entry);
+       return $entry;
+}
+
+sub toString {
+       my $self = shift;
+       for my $root ( $self->{doc}->findnodes($self->{item_xpath}) ) {
+               for my $item ( $self->items ) {
+                       $root->appendChild( $item->{doc}->documentElement );
+               }
+               last;
+       }
+
+       return $self->{doc}->toString;
+}
+
+sub id {};
+sub link {};
+sub title {};
+sub update_ts {};
+sub creator {};
+
+#----------------------------------------------------------
+
+package OpenILS::WWW::SuperCat::Feed::atom;
+use base 'OpenILS::WWW::SuperCat::Feed';
+
+sub new {
+       my $class = shift;
+       my $self = $class->SUPER::build('<atom:feed xmlns:atom="http://www.w3.org/2005/Atom"/>');
+       $self->{type} = 'atom';
+       $self->{item_xpath} = '/atom:feed';
+       return $self;
+}
+
+sub title {
+       my $self = shift;
+       my $text = shift;
+       $self->_create_node('/atom:feed','http://www.w3.org/2005/Atom','atom:title', $text);
+}
+
+sub update_ts {
+       my $self = shift;
+       my $text = shift;
+       $self->_create_node('/atom:feed','http://www.w3.org/2005/Atom','atom:updated', $text);
+}
+
+sub creator {
+       my $self = shift;
+       my $text = shift;
+       $self->_create_node('/atom:feed','http://www.w3.org/2005/Atom','atom:author');
+       $self->_create_node('/atom:feed/atom:author', 'http://www.w3.org/2005/Atom','atom:name', $text);
+}
+
+sub link {
+       my $self = shift;
+       my $type = shift;
+       my $id = shift;
+
+       $self->_create_node(
+               '/atom:feed',
+               'http://www.w3.org/2005/Atom',
+               'atom:link',
+               undef,
+               { rel => $type,
+                 href => $self->base . '/' . $type . '/' . $id,
+                 type => "application/$type+xml",
+               }
+       );
+}
+
+sub id {
+       my $self = shift;
+       my $id = shift;
+
+       $self->_create_node( '/atom:feed', 'http://www.w3.org/2005/Atom', 'atom:id', $id );
+}
+
+package OpenILS::WWW::SuperCat::Feed::atom::item;
+use base 'OpenILS::WWW::SuperCat::Feed::atom';
+
+sub new {
+       my $class = shift;
+       my $xml = shift;
+       my $self = $class->SUPER::build($xml);
+       $self->{doc}->documentElement->setNamespace('http://www.w3.org/2005/Atom', 'atom');
+       $self->{type} = 'atom::item';
+       return $self;
+}
+
+sub link {
+       my $self = shift;
+       my $type = shift;
+       my $id = shift;
+
+       if ($type eq 'unapi') {
+               $self->_create_node(
+                       'atom:entry',
+                       'http://www.w3.org/2005/Atom',
+                       'atom:link',
+                       undef,
+                       { rel => $type,
+                         type => "application/xml",
+                         href => $self->unapi . '?uri=' . $id,
+                       }
+               );
+       }
+}
+
+
+#----------------------------------------------------------
+
+package OpenILS::WWW::SuperCat::Feed::rss2;
+use base 'OpenILS::WWW::SuperCat::Feed';
+
+sub new {
+       my $class = shift;
+       my $self = $class->SUPER::build('<rss version="2.0"><channel/></rss>');
+       $self->{type} = 'rss2';
+       $self->{item_xpath} = '/rss/channel';
+       return $self;
+}
+
+sub title {
+       my $self = shift;
+       my $text = shift;
+       $self->_create_node('/rss/channel',undef,'title', $text);
+}
+
+sub update_ts {
+       my $self = shift;
+       my $text = shift;
+       $self->_create_node('/rss/channel',undef,'lastBuildDate', $text);
+}
+
+sub creator {
+       my $self = shift;
+       my $text = shift;
+       $self->_create_node('/rss/channel', undef,'generator', $text);
+}
+
+sub link {
+       my $self = shift;
+       my $type = shift;
+       my $id = shift;
+
+       $self->_create_node(
+               '/rss/channel',
+               undef,
+               'link',
+               $self->base . '/' . $type . '/' . $id,
+               { rel => $type }
+       );
+}
+
+package OpenILS::WWW::SuperCat::Feed::rss2::item;
+use base 'OpenILS::WWW::SuperCat::Feed::rss2';
+
+sub new {
+       my $class = shift;
+       my $xml = shift;
+       my $self = $class->SUPER::build($xml);
+       $self->{type} = 'atom::item';
+       return $self;
+}
+
+sub link {
+       my $self = shift;
+       my $type = shift;
+       my $id = shift;
+
+       $self->_create_node( item => undef, 'link' => $self->unapi . '?uri=' . $id )
+               if ($type eq 'unapi');
+}
+
+
+#----------------------------------------------------------
+
+package OpenILS::WWW::SuperCat::Feed::mods;
+use base 'OpenILS::WWW::SuperCat::Feed';
+
+sub new {
+       my $class = shift;
+       my $self = $class->SUPER::build('<mods:modsCollection version="3.0" xmlns:mods="http://www.loc.gov/mods/"/>');
+       $self->{type} = 'mods';
+       $self->{item_xpath} = '/mods:modsCollection';
+       return $self;
+}
+
+package OpenILS::WWW::SuperCat::Feed::mods::item;
+use base 'OpenILS::WWW::SuperCat::Feed::mods';
+
+sub new {
+       my $class = shift;
+       my $xml = shift;
+       my $self = $class->SUPER::build($xml);
+       $self->{doc}->documentElement->setNamespace('http://www.loc.gov/mods/', 'mods');
+       $self->{type} = 'mods::item';
+       return $self;
+}
+
+my $linkid = 1;
+
+sub link {
+       my $self = shift;
+       my $type = shift;
+       my $id = shift;
+
+       if ($type eq 'unapi') {
+               $self->_create_node(
+                       'mods:mods',
+                       'http://www.loc.gov/mods/',
+                       'mods:relatedItem',
+                       undef,
+                       { type => 'otherFormat', id => 'link-'.$linkid }
+               );
+               $self->_create_node(
+                       "mods:mods/mods:relatedItem[\@id='link-$linkid']",
+                       'http://www.loc.gov/mods/',
+                       'mods:recordIdentifier',
+                       $self->unapi .'?uri=' . $id
+               );
+               $linkid++;
+       }
+}
+
+
+#----------------------------------------------------------
+
+package OpenILS::WWW::SuperCat::Feed::html;
+use base 'OpenILS::WWW::SuperCat::Feed';
+
+sub new {
+       my $class = shift;
+       my $self = $class->SUPER::build('<html><head/><body/></html>');
+       $self->{type} = 'html';
+       $self->{item_xpath} = '/html/body';
+       return $self;
+}
+
+
 1;