[open-ils-commits] r12987 - in trunk/Open-ILS: examples src/perlmods/OpenILS/Application src/perlmods/OpenILS/Application/Search src/perlmods/OpenILS/Utils (dbs)

svn at svn.open-ils.org svn at svn.open-ils.org
Sat Apr 25 21:31:27 EDT 2009


Author: dbs
Date: 2009-04-25 21:31:26 -0400 (Sat, 25 Apr 2009)
New Revision: 12987

Added:
   trunk/Open-ILS/src/perlmods/OpenILS/Application/Search/Serial.pm
Modified:
   trunk/Open-ILS/examples/fm_IDL.xml
   trunk/Open-ILS/src/perlmods/OpenILS/Application/Search.pm
   trunk/Open-ILS/src/perlmods/OpenILS/Utils/MFHDParser.pm
Log:
Basic support for returning MFHD for display purposes

Interim measure, while there is a direct linkage between sre and bre,
is to invoke the bib_to_mfhd_hash method at record display time;
probably should return a structure including a count of parsed MFHD
records to shortcut cycling through all the arrays, but baby steps


Modified: trunk/Open-ILS/examples/fm_IDL.xml
===================================================================
--- trunk/Open-ILS/examples/fm_IDL.xml	2009-04-26 01:25:48 UTC (rev 12986)
+++ trunk/Open-ILS/examples/fm_IDL.xml	2009-04-26 01:31:26 UTC (rev 12987)
@@ -2574,6 +2574,22 @@
             </actions>
         </permacrud>
 	</class>
+	<class id="svr" controller="open-ils.cstore" oils_obj:fieldmapper="serial::virtual_record" oils_persist:virtual="true" reporter:label="Serial Virtual Record">
+		<fields>
+			<field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
+			<field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
+			<field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
+			<field name="holdings" oils_obj:array_position="3" oils_persist:virtual="true" />
+			<field name="current_holdings" oils_obj:array_position="4" oils_persist:virtual="true" />
+			<field name="supplements" oils_obj:array_position="5" oils_persist:virtual="true" />
+			<field name="current_supplements" oils_obj:array_position="6" oils_persist:virtual="true" />
+			<field name="indexes" oils_obj:array_position="7" oils_persist:virtual="true" />
+			<field name="current_indexes" oils_obj:array_position="8" oils_persist:virtual="true" />
+			<field name="online" oils_obj:array_position="9" oils_persist:virtual="true" />
+			<field name="missing" oils_obj:array_position="10" oils_persist:virtual="true" />
+			<field name="incomplete" oils_obj:array_position="11" oils_persist:virtual="true" />
+		</fields>
+	</class>
 	<class id="sre" controller="open-ils.cstore" oils_obj:fieldmapper="serial::record_entry" oils_persist:tablename="serial.record_entry" reporter:label="Record Entry">
 		<fields oils_persist:primary="id" oils_persist:sequence="serial.record_entry_id_seq">
 			<field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />

Added: trunk/Open-ILS/src/perlmods/OpenILS/Application/Search/Serial.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Search/Serial.pm	                        (rev 0)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Search/Serial.pm	2009-04-26 01:31:26 UTC (rev 12987)
@@ -0,0 +1,109 @@
+package OpenILS::Application::Search::Serial;
+use base qw/OpenILS::Application/;
+use strict; use warnings;
+
+
+use OpenSRF::Utils::JSON;
+use OpenILS::Utils::Fieldmapper;
+use OpenILS::Utils::MFHDParser;
+use OpenSRF::Utils::SettingsClient;
+use OpenILS::Utils::CStoreEditor q/:funcs/;
+use OpenSRF::Utils::Cache;
+use Encode;
+
+use OpenSRF::Utils::Logger qw/:logger/;
+
+use Data::Dumper;
+
+use OpenSRF::Utils::JSON;
+
+use Time::HiRes qw(time);
+use OpenSRF::EX qw(:try);
+use Digest::MD5 qw(md5_hex);
+
+use XML::LibXML;
+use XML::LibXSLT;
+
+use OpenILS::Const qw/:const/;
+
+use OpenILS::Application::AppUtils;
+my $apputils = "OpenILS::Application::AppUtils";
+my $U = $apputils;
+
+my $pfx = "open-ils.search_";
+
+=over
+
+=item * mfhd_to_hash
+
+=back
+
+Takes an MFHD record ID and returns a hash of holdings statements
+
+=cut
+
+sub mfhd_to_hash {
+	my ($self, $client, $id) = @_;
+	
+	my $session = OpenSRF::AppSession->create("open-ils.cstore");
+	my $request = $session->request(
+			"open-ils.cstore.direct.serial.record_entry.retrieve", $id )->gather(1);
+
+	my $u = OpenILS::Utils::MFHDParser->new();
+	my $mfhd_hash = $u->generate_svr( $request->marc );
+
+	$session->disconnect();
+	return $mfhd_hash;
+}
+
+__PACKAGE__->register_method(
+	method	=> "mfhd_to_hash",
+	api_name	=> "open-ils.search.serial.record.mfhd.retrieve",
+	argc		=> 1, 
+	note		=> "Given a serial record ID, return MFHD holdings"
+);
+
+=over
+
+=item * bib_to_mfhd_hash 
+
+=back
+
+Given a bib record ID, returns a hash of holdings statements
+
+=cut
+
+sub bib_to_mfhd_hash {
+	my ($self, $client, $bib) = @_;
+	
+	my $mfhd_hash;
+
+	# miker suggested this way, but I'm too stupid to get it to work
+#	my $e = OpenILS::Utils::CStoreEditor->new();
+#	my $mfhd = $e->search_serial_record_entry({bib=>$bib});
+
+	my @mfhd = $U->cstorereq( "open-ils.cstore.json_query.atomic", {
+		select  => { sre => 'marc' },
+		from    => 'sre',
+		where   => { record => $bib },
+		distinct => 1
+	});
+	
+	if (!@mfhd or scalar(@mfhd) == 0) {
+		return undef;
+	}
+
+	my $u = OpenILS::Utils::MFHDParser->new();
+	$mfhd_hash = $u->generate_svr( $mfhd[0][0]->{marc} );
+
+	return $mfhd_hash;
+}
+
+__PACKAGE__->register_method(
+	method	=> "bib_to_mfhd_hash",
+	api_name	=> "open-ils.search.serial.record.bib_to_mfhd.retrieve",
+	argc		=> 1, 
+	note		=> "Given a bibliographic record ID, return MFHD holdings"
+);
+
+1;

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Search.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Search.pm	2009-04-26 01:25:48 UTC (rev 12986)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Search.pm	2009-04-26 01:31:26 UTC (rev 12987)
@@ -15,6 +15,7 @@
 use OpenILS::Application::Search::Z3950;
 use OpenILS::Application::Search::Zips;
 use OpenILS::Application::Search::CNBrowse;
+use OpenILS::Application::Search::Serial;
 
 
 use OpenILS::Application::AppUtils;

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Utils/MFHDParser.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Utils/MFHDParser.pm	2009-04-26 01:25:48 UTC (rev 12986)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Utils/MFHDParser.pm	2009-04-26 01:31:26 UTC (rev 12987)
@@ -1,168 +1,196 @@
-#!/usr/bin/perl -w
-use strict;
-use Date::Manip;
+package OpenILS::Utils::MFHDParser;
+use strict; use warnings;
 
-# Parse MFHD patterns for http://www.loc.gov/marc/holdings/hd853855.html
+use OpenSRF::EX qw/:try/;
+use Time::HiRes qw(time);
+use OpenILS::Utils::Fieldmapper;
+use OpenSRF::Utils::SettingsClient;
+use OpenSRF::Utils::Logger qw/$logger/;
 
-# Primary goal:
-# Expected input: a chunk of MFHD, a start date, and # of issuances to project
-# Expected output: a set of issuances projected forward from the start date,
-#   with issue/volume/dates/captions conforming to what the MFHD actually says
+use OpenILS::Utils::MFHD;
+use MARC::File::XML;
+use Data::Dumper;
 
-# The thought had been to use Date::Manip to generate the actual dates for
-# each issuance, like:
-#
-#   # To find the 2nd Tuesday of every month
-#   @date = ParseRecur("0:1*2:2:0:0:0",$base,$start,$stop);
+sub new { return bless( {}, shift() ); }
 
-# Secondary goal: generate automatic summary holdings
-#   (a la http://www.loc.gov/marc/holdings/hd863865.html)
+=head1 Subroutines
 
-# Compressability comes from first indicator
-sub parse_compressability {
-	my $c = shift || return undef;
+=over
 
-	my %compressability = (
-		'0' => 'Cannot compress or expand',
-		'1' => 'Can compress but cannot expand',
-		'2' => 'Can compress or expand',
-		'3' => 'Unknown',
-		'#' => 'Undefined'
-	);
+=item * format_textual_holdings($field)
 
-	if (exists $compressability{$c}) {
-		return $compressability{$c};
+=back
+
+Returns concatenated subfields $a with $z for textual holdings (866-868)
+
+=cut
+
+sub format_textual_holdings {
+	my ($self, $field) = @_;
+	my $holdings;
+	my $public_note;
+
+	$holdings = $field->subfield('a');
+	if (!$holdings) {
+		return undef;
 	}
-	# 'Unknown compressability indicator - expected one of (0,1,2,3,#)';
-	return undef;
+
+	$public_note = $field->subfield('z');
+	if ($public_note) {
+		return "$holdings - $public_note";
+	}
+	return $holdings;
 }
 
-# Caption evaluation comes from second indicator
-sub caption_evaluation {
-	my $ce = shift || return undef;
+=over
 
-	my %caption_evaluation = (
-		'0' => 'Captions verified; all levels present',
-		'1' => 'Captions verified; all levels may not be present',
-		'2' => 'Captions unverified; all levels present',
-		'3' => 'Captions unverified; all levels may not be present',
-		'#' => 'Undefined',
-	);
+=item * mfhd_to_hash($mfhd_xml)
 
-	if (exists $caption_evaluation{$ce}) {
-		return $caption_evaluation{$ce};
+=back
+
+Returns a Perl hash containing fields of interest from the MFHD record
+
+=cut
+sub mfhd_to_hash {
+	my ($self, $mfhd_xml) = @_;
+
+	my $holdings = [];
+	my $supplements = [];
+	my $indexes = [];
+	my $current_holdings = [];
+	my $current_supplements = [];
+	my $current_indexes = [];
+	my $online = []; # Laurentian extension to MFHD standard
+	my $missing = []; # Laurentian extension to MFHD standard
+	my $incomplete = []; # Laurentian extension to MFHD standard
+
+	my $marc = MARC::Record->new_from_xml($mfhd_xml);
+	my $mfhd = OpenILS::Utils::MFHD->new($marc);
+
+	foreach my $field ($marc->field('866')) {
+		my $textual_holdings = $self->format_textual_holdings($field);
+		if ($textual_holdings) {
+			push @$holdings, $textual_holdings;
+		}
 	}
-	# 'Unknown caption evaluation indicator - expected one of (0,1,2,3,#)';
-	return undef;
-}
+	foreach my $field ($marc->field('867')) {
+		my $textual_holdings = $self->format_textual_holdings($field);
+		if ($textual_holdings) {
+			push @$supplements, $textual_holdings;
+		}
+	}
+	foreach my $field ($marc->field('868')) {
+		my $textual_holdings = $self->format_textual_holdings($field);
+		if ($textual_holdings) {
+			push @$indexes, $textual_holdings;
+		}
+	}
 
-# Start with frequency ($w)
-# then overlay number of pieces of issuance ($p)
-# then regularity pattern ($y)
-my %frequency = (
-	'a' => 'annual',
-	'b' => 'bimonthly',
-	'c' => 'semiweekly',
-	'd' => 'daily',
-	'e' => 'biweekly',
-	'f' => 'semiannual',
-	'g' => 'biennial',
-	'h' => 'triennial',
-	'i' => 'three times a week',
-	'j' => 'three times a month',
-	'k' => 'continuously updated',
-	'm' => 'monthly',
-	'q' => 'quarterly',
-	's' => 'semimonthly',
-	't' => 'three times a year',
-	'w' => 'weekly',
-	'x' => 'completely irregular',
-);
+	foreach my $cap_id ($mfhd->captions('853')) {
+		my @curr_holdings = $mfhd->holdings('863', $cap_id);
+		next unless scalar @curr_holdings;
+		foreach (@curr_holdings) {
+			push @$current_holdings, $_->format();
+		}
+	}
 
-sub parse_frequency {
-	my $freq = shift || return undef;
+	foreach my $cap_id ($mfhd->captions('854')) {
+		my @curr_supplements = $mfhd->holdings('864', $cap_id);
+		next unless scalar @curr_supplements;
+		foreach (@curr_supplements) {
+			push @$current_supplements, $_->format();
+		}
+	}
 
-	if ($freq =~ m/^\d+$/) {
-		return "$freq times a year";
-	} elsif (exists $frequency{$freq}) {
-		return $frequency{$freq};
+	foreach my $cap_id ($mfhd->captions('855')) {
+		my @curr_indexes = $mfhd->holdings('865', $cap_id);
+		next unless scalar @curr_indexes;
+		foreach (@curr_indexes) {
+			push @$current_indexes, $_->format();
+		}
 	}
-	# unrecognized frequency specification
-	return undef;
-}
 
-# $x - Point at which the highest level increments or changes
-# Interpretation of two-digit numbers in the 01-12 range depends on the publishing frequency
-# More than one change can be passed in the subfield and are delimited by commas
-sub chronology_change {
-	my $chronology_change = shift || return undef;
-	my @c_changes = split /,/, $chronology_change;
-	foreach my $change (@c_changes) {
-		if ($change == 21) {
-			
+	# Laurentian extensions
+	foreach my $field ($marc->field('530')) {
+		my $online_stmt = $self->format_textual_holdings($field);
+		if ($online_stmt) {
+			push @$online, $online_stmt;
 		}
 	}
-	return undef;
+
+	foreach my $field ($marc->field('590')) {
+		my $missing_stmt = $self->format_textual_holdings($field);
+		if ($missing_stmt) {
+			push @$missing, $missing_stmt;
+		}
+	}
+
+	foreach my $field ($marc->field('591')) {
+		my $incomplete_stmt = $self->format_textual_holdings($field);
+		if ($incomplete_stmt) {
+			push @$incomplete, $incomplete_stmt;
+		}
+	}
+
+	return { holdings => $holdings, current_holdings => $current_holdings,
+			supplements => $supplements, current_supplements => $current_supplements,
+			indexes => $indexes, current_indexes => $current_indexes,
+			missing => $missing, incomplete => $incomplete, };
 }
 
-# Publication code : first character in regularity pattern ($y)
-sub parse_publication_code {
-	my $c = shift || return undef;
+=over
 
-	my %publication_code = (
-		'c' => 'combined',
-		'o' => 'omitted',
-		'p' => 'published',
-		'#' => 'undefined',
-	);
+=item * init_holdings_virtual_record()
 
-	if (exists $publication_code{$c}) {
-		return $publication_code{$c};
-	}
-	return undef;
+=back
+
+Initialize the serial virtual record (svr) instance
+
+=cut
+sub init_holdings_virtual_record {
+	my $record = Fieldmapper::serial::virtual_record->new;
+	$record->holdings([]);
+	$record->current_holdings([]);
+	$record->supplements([]);
+	$record->current_supplements([]);
+	$record->indexes([]);
+	$record->current_indexes([]);
+	$record->online([]);
+	$record->missing([]);
+	$record->incomplete([]);
+	return $record;
 }
 
-# Chronology code : part of regularity pattern ($y)
-sub parse_chronology_code {
-	my $c = shift || return undef;
+=over
 
-	my %chronology_code = (
-		'd' => 'Day',
-		'm' => 'Month',
-		's' => 'Season',
-		'w' => 'Week',
-		'y' => 'Year',
-		'e' => 'Enumeration',
-	);
+=item * init_holdings_virtual_record($mfhd)
 
-	if (exists $chronology_code{$c}) {
-		return $chronology_code{$c};
+=back
+
+Given an MFHD record, return a populated svr instance
+
+=cut
+sub generate_svr {
+	my ($self, $mfhd) = @_;
+
+	if (!$mfhd) {
+		return undef;
 	}
-	return undef;
-}
 
-sub parse_regularity_pattern {
-	my $pattern = shift;
-	my ($pc, $cc, $cd) = $pattern =~ m{^(\w)(\w)(.+)$};
-	
-	my $pub_code = parse_publication_code($pc);
-	my $chron_code = parse_chronology_code($cc);
-	my $chron_def = parse_chronology_definition($cd);
-	
-	return ($pub_code, $chron_code, $chron_def);
-}
+	my $record = init_holdings_virtual_record();
+	my $holdings = $self->mfhd_to_hash($mfhd);
 
-sub parse_chronology_definition {
-	my $chron_def = shift || return undef;
-	# Well, this is where it starts to get hard, doesn't it?
-	return $chron_def;
+	$record->holdings($holdings->{holdings});
+	$record->current_holdings($holdings->{current_holdings});
+	$record->supplements($holdings->{supplements});
+	$record->current_supplements($holdings->{current_supplements});
+	$record->indexes($holdings->{indexes});
+	$record->current_indexes($holdings->{current_indexes});
+	$record->online($holdings->{online});
+	$record->missing($holdings->{missing});
+	$record->incomplete($holdings->{incomplete});
+
+	return $record;
 }
 
-print parse_regularity_pattern("cddd");
-print "\n";
-print parse_regularity_pattern("38dd");
-print "\n";
-
 1;
-
-# :vim:noet:ts=4:sw=4:



More information about the open-ils-commits mailing list