1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
|
#!/usr/bin/perl -w
# The following example is an expanded version of "addlocal.pl" that
# checks and fixes existing records in addition to processing new ones.
# It looks for a call number subfield 'h' of each 852 field (#852.h).
# It also checks #900.a and #999.f for the data. It then converts the
# call number fields to upper case and confirms they are all identical.
# For mismatches and missing 852 data, the records are not modified,
# but an ascii version is written so the librarian can determine what
# is correct. Missing 900 and 999 data is created. An ascii version of
# the altered records is written for checking. This is a somewhat
# contrived example. But it shows what can be done with manipulating
# field data and using option templates.
use MARC 0.98;
use strict;
my $infile = "specials.001";
my $outfile = "output.004"; # results in usmarc format
my $outtext = "output5.txt"; # original input in ascii for ok callno.
my $outtext2 = "output6.txt"; # changed records in ascii
my $outtext3 = "output7.txt"; # invalid or mismatched records in ascii
my $outtext4 = "output8.txt"; # ascii for all ok callno (change or not)
unlink $outfile, $outtext, $outtext2, $outtext3, $outtext4;
# This subroutine takes an array of all the call numbers found. It
# returns an upper-cased version if all compare or '' if not
sub check_callno {
my $num1 = uc(shift);
foreach (@_) {
return '' unless ($num1 eq uc($_));
}
return $num1;
}
# This subroutine does most of the dirty work. There are four required
# parameters: $marc, $template, $subfield, and $value. It will return
# "undef" unless all four are specified. Zero (0 or "0") is a possible
# $subfield or $value. Blank ('') can be used for the $value.
sub fix_subfield {
my $marc = shift || return;
my $template = shift || return;
my $subfield = shift;
my $value = shift;
return unless (defined $subfield and defined $value);
my $altered = 0;
# If the $subfield already exists, get the data in a format suitable
# for making updates. Note the use of $template.
my ($found) = $marc->searchmarc($template);
if (defined $found) {
my @u = $marc->getupdate($template);
my @f = ();
my $ff;
my $fixed = 0;
# $fixed accounts for the situation when the call number may be present
# in some of the 852 fields, but not all of them. $fixed gets set when
# the $subfield is found within a single field. If processing reaches
# the end of the field (the "\036" delimiter) without $fixed, then the
# $subfield and $value are appended to that field.
while (@u) {
last unless defined ($ff = shift @u);
if ($ff eq "\036") {
unless ($fixed) {
push @f, $subfield, $value;
$altered++;
}
push @f, $ff;
$fixed = 0;
next;
}
push @f, $ff;
# All subfields that don't match out target just get copied.
unless ($subfield eq $ff) {
push @f, shift @u;
next;
}
last unless defined ($ff = shift @u);
# Fix the target if necessary and set $altered if anything changed.
if ($value eq $ff) {
push @f, $ff;
}
else {
$altered++;
push @f, $value;
}
$fixed++;
}
# Actually fix the record if required. Again note the use of $template.
if ($altered) {
$marc->updaterecord ($template, @f)
|| warn "update failed: $template->{field}, $subfield\n";
}
}
# This next part is tricky. If fix_subfield is called with just the
# four required parameters, you bypass the next step. The preceeding
# part is run if searchmarc() finds the field specified in the
# $template. But if the field does not exist, and there are optional
# parameters in the call to fix_subfield, those parameters are used
# as a series of subfields for an addfield(). In plain language, you
# can tell fix_subfield what to add if the field doesn't exist.
elsif (@_) {
$marc->addfield($template, @_)
|| warn "addfield failed: $template->{field}, $subfield\n";
$altered++;
}
return $altered;
}
# The $template hashes for this example:
my $loc852 = {record=>1, field=>'852', ordered=>'y'};
my $loc900 = {record=>1, field=>'900', ordered=>'y'};
my $loc999 = {record=>1, field=>'999', ordered=>'n'};
# The create_if_not_found field specifications:
my @default900 = ('i1',' ','i2',' ','a');
my @default999 = ('i1',' ','i2',' ','c','wL70','d','AR Clinton PL','f');
my $invalid = 0;
my $updated = 0;
my $totalcount = 0;
my $x = MARC->new;
$x->openmarc({file=>$infile,'format'=>"usmarc"}) || die;
# We process records one at a time for this operation. Multiple 852 fields
# are legal (for multiple copies).
while ($x->nextmarc(1)) {
my $change = 0;
my @callno = $x->getvalue($loc852,'subfield','h');
# But multiple 900 and 999 fields are not permitted. So we force a
# miscompare if we discover one.
my ($from900, $dup900) = $x->getvalue($loc900,'subfield','a');
if (defined $from900) { push @callno, $from900; }
if (defined $dup900) { push @callno, ''; }
my ($from999, $dup999) = $x->getvalue($loc999,'subfield','f');
if (defined $from999) { push @callno, $from999; }
if (defined $dup999) { push @callno, ''; }
# We now have an array of all the call numbers found. The subroutine
# returns an upper-cased version if all compare or '' if not.
my $callno = check_callno(@callno);
# Write a "good" result back to everywhere that it should be. Keep track
# of which records were modified. And notice that a $template conveys
# a lot of repeated information.
if ($callno) {
$x->output({file=>">>$outtext",'format'=>"ascii"});
# $outtext is a "before" ascii file to compare changes with the "after"
# ascii file $outtext4.
if (fix_subfield($x,$loc852,'h',"$callno")) {
$change++;
}
# The 852 subfield passes just the four required parameters. Hence
# nothing is added if the 852 field is missing.
if (fix_subfield($x,$loc900,'a',"$callno",@default900,"$callno")) {
$change++;
}
# The 900 and 999 fields are created with default values if they
# do not already exist.
if (fix_subfield($x,$loc999,'f',"$callno",@default999,"$callno")) {
$change++;
}
$x->output({file=>">>$outfile",'format'=>"usmarc"});
$x->output({file=>">>$outtext2",'format'=>"ascii"}) if $change;
$x->output({file=>">>$outtext4",'format'=>"ascii"});
$updated++ if $change;
}
# Write the records with invalid or mismatched call numbers. In this
# example, they go into the same usmarc format file $outfile.
else {
$x->output({file=>">>$outfile",'format'=>"usmarc"});
$x->output({file=>">>$outtext3",'format'=>"ascii"});
$invalid++;
}
$x->deletemarc(); #empty the object for reading in another
$totalcount++;
}
# We write all the records to the output file in MARC format. The ascii
# output in $outtext3 gives the librarian both a list of records
# requiring manual call number assignment/resolution and all the Title,
# Author, Publication and related data needed to assign location based
# on standard references. For checking, we write all the modified
# records to $outtext2.
print "\nprocessed $totalcount records\n";
print "$updated had call numbers which were changed\n";
print "$invalid had missing or invalid call numbers\n";
|