2 # Copyright (C) 2010 Laurentian University
3 # Author: Dan Scott <dscott@laurentian.ca>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 # ---------------------------------------------------------------
23 use OpenILS::Utils::Fieldmapper;
24 use OpenSRF::Utils::SettingsClient;
26 use Unicode::Normalize;
27 use OpenILS::Application::AppUtils;
32 For a given set of records (specified by ID at the command line, or special option --all):
36 =item * Iterate through the list of fields that are controlled fields
38 =item * Iterate through the list of subfields that are controlled for
41 =item * Search for a matching authority record for that combination of
46 =item * If we find a match, then add a $0 subfield to that field identifying
47 the controlling authority record
49 =item * If we do not find a match, then insert a row into an "uncontrolled"
50 table identifying the record ID, field, and subfield(s) that were not controlled
54 =item * Iterate through the list of floating subdivisions
58 =item * If we find a match, then add a $0 subfield to that field identifying
59 the controlling authority record
61 =item * If we do not find a match, then insert a row into an "uncontrolled"
62 table identifying the record ID, field, and subfield(s) that were not controlled
66 =item * If we changed the record, update it in the database
73 my $bootstrap = '/openils/conf/opensrf_core.xml';
75 my $result = GetOptions(
76 'configuration=s' => \$bootstrap,
77 'record=s' => \@records,
78 'all' => \$all_records
81 OpenSRF::System->bootstrap_client(config_file => $bootstrap);
82 Fieldmapper->import(IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
84 # must be loaded and initialized after the IDL is parsed
85 use OpenILS::Utils::CStoreEditor;
86 OpenILS::Utils::CStoreEditor::init();
88 my $editor = OpenILS::Utils::CStoreEditor->new;
91 # get a list of all non-deleted records from Evergreen
92 # open-ils.cstore open-ils.cstore.direct.biblio.record_entry.id_list.atomic {"deleted":"f"}
93 $undeleted = $editor->request(
94 'open-ils.cstore.direct.biblio.record_entry.id_list.atomic',
95 [{deleted => 'f'}, {id => { '>' => 0}}]
97 @records = @$undeleted;
99 # print Dumper($undeleted, \@records);
101 # Hash of controlled fields & subfields in bibliographic records, and their
102 # corresponding controlling fields & subfields in the authority record
104 # So, if the bib 650$a can be controlled by an auth 150$a, that maps to:
105 # 650 => { a => { 150 => 'a'}}
107 100 => { a => { 100 => 'a' },
124 110 => { a => { 110 => 'a' },
139 111 => { a => { 111 => 'a' },
155 130 => { a => { 130 => 'a' },
170 600 => { a => { 100 => 'a' },
195 610 => { a => { 110 => 'a' },
217 611 => { a => { 111 => 'a' },
237 630 => { a => { 130 => 'a' },
256 648 => { a => { 148 => 'a' },
262 650 => { a => { 150 => 'a' },
269 651 => { a => { 151 => 'a' },
275 655 => { a => { 155 => 'a' },
281 700 => { a => { 100 => 'a' },
298 710 => { a => { 110 => 'a' },
313 711 => { a => { 111 => 'a' },
329 730 => { a => { 130 => 'a' },
344 751 => { a => { 151 => 'a' },
352 foreach my $rec_id (@records) {
355 my $e = OpenILS::Utils::CStoreEditor->new(xact=>1);
356 # State variable; was the record changed?
360 my $record = $e->retrieve_biblio_record_entry($rec_id);
362 # print Dumper($record);
364 my $marc = MARC::Record->new_from_xml($record->marc());
366 # get the list of controlled fields
367 my @c_fields = keys %controllees;
369 foreach my $c_tag (@c_fields) {
370 my @c_subfields = keys %{$controllees{"$c_tag"}};
371 # print "Field: $field subfields: ";
372 # foreach (@subfields) { print "$_ "; }
374 # Get the MARCXML from the record and check for controlled fields/subfields
375 my @bib_fields = ($marc->field($c_tag));
376 foreach my $bib_field (@bib_fields) {
377 # print $_->as_formatted();
381 foreach my $c_subfield (@c_subfields) {
382 my $sf = $bib_field->subfield($c_subfield);
384 # Give me the first element of the list of authority controlling tags for this subfield
385 # XXX Will we need to support more than one controlling tag per subfield? Probably. That
386 # will suck. Oh well, leave that up to Ole to implement.
387 $match_subfields{$c_subfield} = (keys %{$controllees{$c_tag}{$c_subfield}})[0];
388 $match_tag = $match_subfields{$c_subfield};
389 push @searches, {term => $sf, subfield => $c_subfield};
392 # print Dumper(\%match_subfields);
395 my @tags = ($match_tag);
397 # print "Controlling tag: $c_tag and match tag $match_tag\n";
398 # print Dumper(\@tags, \@searches);
400 # Now we've built up a complete set of matching controlled
401 # subfields for this particular field; let's check to see if
402 # we have a matching authority record
403 my $session = OpenSRF::AppSession->create("open-ils.search");
404 my $validates = $session->request("open-ils.search.authority.validate.tag.id_list",
405 "tags", \@tags, "searches", \@searches
407 $session->disconnect();
409 # print Dumper($validates);
411 if (scalar(@$validates) == 0) {
415 # Iterate through the returned authority record IDs to delete any
416 # matching $0 subfields already in the bib record
417 foreach my $auth_zero (@$validates) {
418 $bib_field->delete_subfield(code => '0', match => qr/\)$auth_zero$/);
421 # Okay, we have a matching authority control; time to
422 # add the magical subfield 0. Use the first returned auth
424 my $auth_id = @$validates[0];
425 my $auth_rec = $e->retrieve_authority_record_entry($auth_id);
426 my $auth_marc = MARC::Record->new_from_xml($auth_rec->marc());
427 my $cni = $auth_marc->field('003')->data();
429 $bib_field->add_subfields('0' => "($cni)$auth_id");
434 # print $marc->as_formatted();
435 my $xml = $marc->as_xml_record();
437 $xml =~ s/^<\?xml.+\?\s*>//go;
438 $xml =~ s/>\s+</></go;
439 $xml =~ s/\p{Cc}//go;
440 $xml = OpenILS::Application::AppUtils->entityize($xml);
443 $e->update_biblio_record_entry($record);