From c748486eb990b37f04dabeea001491b36c74ccdd Mon Sep 17 00:00:00 2001 From: miker Date: Mon, 6 Mar 2006 05:50:43 +0000 Subject: [PATCH] adding atom format support and bookbag feeds (atom/rss2/mods/html(soon)) git-svn-id: svn://svn.open-ils.org/ILS/trunk@3264 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- .../perlmods/OpenILS/Application/SuperCat.pm | 12 + Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm | 421 +++++++++++++++++- 2 files changed, 432 insertions(+), 1 deletion(-) diff --git a/Open-ILS/src/perlmods/OpenILS/Application/SuperCat.pm b/Open-ILS/src/perlmods/OpenILS/Application/SuperCat.pm index 61ba2f4f67..1d00204aae 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/SuperCat.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/SuperCat.pm @@ -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 diff --git a/Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm b/Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm index 9c7dffaea1..da97a972de 100644 --- a/Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm +++ b/Open-ILS/src/perlmods/OpenILS/WWW/SuperCat.pm @@ -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(''); + $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(''); + $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(''); + $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(''); + $self->{type} = 'html'; + $self->{item_xpath} = '/html/body'; + return $self; +} + + 1; -- 2.43.2