#!/usr/bin/perl # article-index.cgi - a searchable/browsable interface to a MyLibrary instance # Eric Lease Morgan # July 18, 2007 - added startRecord and maximumRecords to SRU request; # indexed resource_id field of resource_location table # July 5, 2007 - added show/hide javascript # July 3, 2007 - tweaked facet_term_combinations; added commify, browse, & pager # July 1, 2007 - first cut; based on mylibrary.cgi # require/use use CGI; use CGI::Carp qw(fatalsToBrowser); use LWP::UserAgent; use MyLibrary::Core; use strict; use XML::LibXML; use XML::LibXSLT; # define constants use constant TEMPLATE => 'etc/template.txt'; use constant HOME => 'etc/home.txt'; use constant TERM => 'etc/term.txt'; use constant RESULTS => 'etc/results.txt'; use constant ABOUT => 'etc/about.txt'; use constant BROWSE => 'etc/browse.txt'; use constant CMDTERM => 'term'; use constant SRUROOT => 'http://mylibrary.library.nd.edu/demos/article-index/sru/server.cgi?operation=searchRetrieve&version=1.1&startRecord=##START##&maximumRecords=##PAGESIZE##&query='; use constant STYLESHEET => 'etc/style.xsl'; use constant PAGESIZE => 25; # initialize my $cgi = CGI->new; my $html; MyLibrary::Config->instance( 'articles' ); # get the command my $cmd = $cgi->param( 'cmd' ); # branch accordingly if (! $cmd ) { # get the themes my $facet = MyLibrary::Facet->new( name => 'Themes' ); # display the home page $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( HOME )/e; $html =~ s/##NUMBER_OF_RESOURCES##/&number_of_items/e; $html =~ s/##FACETS##/&facet_term_combinations( $facet )/e; } elsif ( $cmd eq 'browse' ) { # get the input my $by = $cgi->param( 'by' ); # get the facet my $facet = MyLibrary::Facet->new( name => $by ); # display the home page $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( BROWSE )/e; $html =~ s/##FACETNAME##/$facet->facet_name/e; $html =~ s/##FACETNOTE##/$facet->facet_note/e; $html =~ s/##FACETS##/&facet_term_combinations( $facet )/e; } elsif ( $cmd eq 'about' ) { # display the home page $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ABOUT )/e; } elsif ( $cmd eq 'search' ) { # get the input my $query = $cgi->param( 'query' ); my $start = $cgi->param( 'start' ); # sanity check if ( ! $start ) { $start = 0 } # munge the query into cql while ( $query =~ /^ / ) { $query =~ s/^ // } while ( $query =~ / $/ ) { $query =~ s/ $// } while ( $query =~ / / ) { $query =~ s/ / / } if ($query =~ /\s/) { if (( $query =~ / and / ) | ( $query =~ / or / ) | ( $query =~ / not / )) { } elsif ( $query =~ /=/ ) { } elsif ( $query !~ /"/ ) { # try to make queries with no syntactical sugar a bit "smarter" my @terms = split / /, $query; my $enhancement; for ( my $i; $i <= $#terms; $i++ ) { if ( $i < $#terms ) { $enhancement .= $terms[$i] . ' and ' } else { $enhancement .= $terms[$i] } } $query = '"' . $query . '"' . " or ($enhancement)"; } } # create an SRU URL my $url = SRUROOT . "$query"; $url =~ s/##PAGESIZE##/PAGESIZE/e; $url =~ s/##START##/$start/e; # create a user agent, create a request, send it, and get a response my $ua = LWP::UserAgent->new( agent => 'SRU-Client/0.1 ' ); my $request = HTTP::Request->new( GET => $url ); my $response = $ua->request( $request ); # transform the response into a snippet of html my $parser = XML::LibXML->new; my $xslt = XML::LibXSLT->new; my $source = $parser->parse_string( $response->content ) or croak $!; my $style = $parser->parse_file( STYLESHEET ) or croak $!; my $stylesheet = $xslt->parse_stylesheet( $style ) or croak $!; my $results = $stylesheet->transform( $source ) or croak $!; # create a list of integers from the xslt; note, the first integer is the total number of records my $ids = $stylesheet->output_string( $results ); chop $ids; my @ids = split /\t/, $ids; my $number_of_hits = splice @ids, 0, 1; # build the hit list my $hit_list; if ( $number_of_hits ) { for ( my $i = 0; $i <= $#ids; $i++ ) { $hit_list .= &list_one_resource( $ids[ $i ]); last if ( $i == $number_of_hits ); } $hit_list = $cgi->ol({ -start => $start + 1 }, $hit_list ); } # display the results page $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( RESULTS )/e; $html =~ s/##QUERY##/$cgi->param( 'query' )/e; $html =~ s/##NUMBEROFHITS##/&commify( $number_of_hits + 1 )/e; $html =~ s/##HITLIST##/$hit_list/e; $html =~ s/##PAGER##/&pager( '?cmd=search&query=' . $cgi->param( 'query' ) . '&start=', $start, $number_of_hits )/e; } elsif ($cmd eq 'term') { # get the input my $term_id = $cgi->param( 'id' ); my $start = $cgi->param( 'start' ); # sanity check if ( ! $start ) { $start = 0 } # initialize my $term = MyLibrary::Term->new( id => $term_id ); my @related_resources = $term->related_resources( sort => 'name' ); my $number_of_resources = $#related_resources; # create the list of resources my $list; for ( my $i = $start; $i < $start + PAGESIZE; $i++ ) { $list .= &list_one_resource( $related_resources[ $i ] ); last if ( $i == $number_of_resources ); } $list = $cgi->ol({ -start => $start + 1 }, $list ); # display the about page $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( TERM )/e; $html =~ s/##TERM##/$term->term_name/e; $html =~ s/##TERM_NOTE##/$term->term_note/e; $html =~ s/##RESOURCE_LIST##/$list/e; $html =~ s/##PAGER##/&pager( "?cmd=term&id=$term_id&start=", $start, $number_of_resources )/e; } else { # error $html = $cgi->start_html( -title => 'MyLibrary' ); $html .= $cgi->h1( 'MyLibrary' ); $html .= $cgi->p( "Unknown value for cmd ($cmd). Call Eric." ); $html .= $cgi->end_html; } # done print $cgi->header( -type => 'text/html', -charset => 'utf-8' ); print $html; ############# # subroutines sub number_of_items { return &commify( scalar( MyLibrary::Resource->get_resources( output => 'id' ))) } sub slurp { # open a file named by the input and return its contents my $f = @_[0]; my $r; open (F, "< $f"); while () { $r .= $_ } close F; return $r; } sub facet_term_combinations { # get the input my @facets = @_; # initialize my $terms; foreach ( @facets ) { # create a list of terms associated with each facet foreach my $id ($_->related_terms(sort => 'name')) { my $term = MyLibrary::Term->new( id => $id ); $terms .= '
  • ' . $term->term_name . ' (' . &commify( scalar( $term->related_resources )) . ' items)
  • '; } } # done return $cgi->ol( $terms ); } sub list_one_resource { # get this resouce my $resource = MyLibrary::Resource->new( id => shift ); # split subfieled... fields my $creators = ''; foreach ( split /\|/, $resource->creator ) { $creators .= "$_; " } my $keywords = ''; foreach ( split /\|/, $resource->subject ) { $keywords .= "$_; " } # initialize my $cells; my $rows; my $details; # description if ( $resource->note ) { $cells = $cgi->td({ -class => 'label' }, 'description: ' ); $cells .= $cgi->td( $resource->note ); $rows .= $cgi->Tr( { -valign => 'top' }, $cells ); } # ceators if ( $resource->creator ) { $cells = $cgi->td({ -class => 'label' }, 'creator(s): ' ); $cells .= $cgi->td( $creators ); $rows .= $cgi->Tr( { -valign => 'top' }, $cells ); } # source if ( $resource->source ) { $cells = $cgi->td({ -class => 'label' }, 'source: ' ); $cells .= $cgi->td( $resource->source ); $rows .= $cgi->Tr( { -valign => 'top' }, $cells ); } # keywords if ( $resource->subject ) { $cells = $cgi->td({ class => 'label' }, 'keywords(s): ' ); $cells .= $cgi->td( $keywords ); $rows .= $cgi->Tr( { -valign => 'top' }, $cells ); } # publisher if ( $resource->subject ) { $cells = $cgi->td({ -class => 'label' }, 'publisher: ' ); $cells .= $cgi->td( $resource->publisher ); $rows .= $cgi->Tr( { -valign => 'top' }, $cells ); } # wrap it in a table and then a hidden div $details = $cgi->table({ -border => 0, -class => 'detail' }, $rows ); $details = $cgi->div({ -id => 'd' . $resource->id, -style => 'display: none' }, $details ); # get the url; NOT CORRECT!!! my @locations = $resource->resource_locations(); my $url= $locations[0]->location; # done; complete with cool show/hide javascript return $cgi->li({ -class => 'citation' }, $cgi->a({ -href => $url }, $resource->name ) . ' ' . $cgi->a( { -href => "javascript:expand('d" . $resource->id . "')", -style => 'color: grey; text-decoration: none' }, 'details...' ) . $details ); } sub commify { # cool hack; http://www.unix.org.ua/orelly/perl/cookbook/ch02_18.htm my $text = reverse $_[0]; $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g; return scalar reverse $text; } sub pager { # get the input my $link = shift; my $start = shift; my $size = shift; # create the links my $previous = $cgi->a({ -href => $link . ( $start - PAGESIZE ) }, 'Previous' ) . '  '; my $next = '  ' . $cgi->a({ -href => $link . ( $start + PAGESIZE ) }, 'Next' ); # build the pager my $pager; if ( $start - PAGESIZE >= 0 ) { $pager = $previous } if ( $start + PAGESIZE < $size ) { $pager .= $next } # done return $pager; }