[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