From eea7b9d20d4e1c19bc96fbec7e96e1341ba4dad1 Mon Sep 17 00:00:00 2001 From: Michael Hafen Date: Wed, 20 Feb 2013 14:32:06 -0700 Subject: [PATCH 1/4] Bug 5608 - command-line tool to switch information in 440 and 490 tags With the MARC21 standard moving from the 440 tag to the 490, this tool is to help libraries make the move. It switches any information in 440 tags to 490 tags, and any information in 490 tags to 440 tags. That seemed like the best way to go to me. To Test: locate some biblios with 440 or 490 tags filled. run bin/migration_tools/switch_marc21_series_info.pl -c observe that the information in the biblios has switched 4xx tags. http://bugs.koha-community.org/show_bug.cgi?id=5608 Signed-off-by: Bernardo Gonzalez Kriegel Comment: Works as described. No errors. Signed-off-by: Paul Poulain Signed-off-by: Jared Camins-Esakov --- .../switch_marc21_series_info.pl | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100755 misc/migration_tools/switch_marc21_series_info.pl diff --git a/misc/migration_tools/switch_marc21_series_info.pl b/misc/migration_tools/switch_marc21_series_info.pl new file mode 100755 index 0000000000..28413a2e84 --- /dev/null +++ b/misc/migration_tools/switch_marc21_series_info.pl @@ -0,0 +1,173 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +# Script to switch the MARC21 440$anv and 490$av information + +BEGIN { + # find Koha's Perl modules + # test carefully before changing this + use FindBin; + eval { require "$FindBin::Bin/../kohalib.pl" }; +} + +use C4::Biblio; +use C4::Context; +use Getopt::Long; + +my $commit; +my $update_frameworks; +my $show_help; +my $verbose; +my $result = GetOptions( + 'c' => \$commit, + 'm' => \$update_frameworks, + 'h|help' => \$show_help, + 'v' => \$verbose, + ); + +if ( ! $result || $show_help ) { + print_usage(); + exit 0; +} + +my $dbh = C4::Context->dbh; + +my $count_sth = $dbh->prepare( 'SELECT COUNT(biblionumber) FROM biblio CROSS JOIN biblioitems USING (biblionumber) WHERE ExtractValue(marcxml,\'//datafield[@tag="440"]/subfield[@code="a"]\') OR ExtractValue(marcxml,\'//datafield[@tag="440"]/subfield[@code="v"]\') OR ExtractValue(marcxml,\'//datafield[@tag="440"]/subfield[@code="n"]\') OR ExtractValue(marcxml,\'//datafield[@tag="490"]/subfield[@code="a"]\') OR ExtractValue(marcxml,\'//datafield[@tag="490"]/subfield[@code="v"]\')' ); + +my $bibs_sth = $dbh->prepare( 'SELECT biblionumber FROM biblio CROSS JOIN biblioitems USING (biblionumber) WHERE ExtractValue(marcxml,\'//datafield[@tag="440"]/subfield[@code="a"]\') OR ExtractValue(marcxml,\'//datafield[@tag="440"]/subfield[@code="v"]\') OR ExtractValue(marcxml,\'//datafield[@tag="440"]/subfield[@code="n"]\') OR ExtractValue(marcxml,\'//datafield[@tag="490"]/subfield[@code="a"]\') OR ExtractValue(marcxml,\'//datafield[@tag="490"]/subfield[@code="v"]\')' ); + +unless ( $commit ) { + print_usage(); +} + +print "Examining MARC records...\n"; +$count_sth->execute(); +my ( $num_records ) = $count_sth->fetchrow; + +unless ( $commit ) { + if ( $num_records ) { + print "This action would change $num_records MARC records\n"; + } + else { + print "There appears to be no series information to change\n"; + } + exit 0; +} + +print "Changing $num_records MARC records...\n"; + +$bibs_sth->execute(); +while ( my ( $biblionumber ) = $bibs_sth->fetchrow ) { + my $framework = GetFrameworkCode( $biblionumber ) || ''; + my ( @newfields ); + + # MARC21 specific + my ( $series1_t, $series1_f ) = ( '440', 'a' ); + my ( $volume1_t, $volume1_f ) = ( '440', 'v' ); + my ( $number1_t, $number1_f ) = ( '440', 'n' ); + + my ( $series2_t, $series2_f ) = ( '490', 'a' ); + my ( $volume2_t, $volume2_f ) = ( '490', 'v' ); + + # Get biblio marc + my $biblio = GetMarcBiblio( $biblionumber ); + + foreach my $field ( $biblio->field( $series1_t ) ) { + my @newsubfields; + my @series1 = $field->subfield( $series1_f ); + my @volume1 = $field->subfield( $volume1_f ); + my @number1 = $field->subfield( $number1_f ); + my $i = 0; + foreach my $num ( @number1 ) { + $volume1[$i] .= " " if ( $volume1[$i] ); + $volume1[$i++] .= $num if ( $num ); + } + + while ( @series1 || @volume1 ) { + if ( @series1 ) { + push @newsubfields, ( $series2_f, shift @series1 ); + } + if ( @volume1 ) { + push @newsubfields, ( $volume2_f, shift @volume1 ); + } + } + + my $new_field = MARC::Field->new( $series2_t, '', '', + @newsubfields ); + + $biblio->delete_fields( $field ); + push @newfields, $new_field; + } + + foreach my $field ( $biblio->field( $series2_t ) ) { + my @newsubfields; + my @series2 = $field->subfield( $series2_f ); + my @volume2 = $field->subfield( $volume2_f ); + + while ( @series2 || @volume2 ) { + if ( @series2 ) { + push @newsubfields, ( $series1_f, shift @series2 ); + } + if ( @volume2 ) { + push @newsubfields, ( $volume1_f, shift @volume2 ); + } + } + + my $new_field = MARC::Field->new( $series1_t, '', '', + @newsubfields ); + + $biblio->delete_fields( $field ); + push @newfields, $new_field; + } + $biblio->insert_fields_ordered( @newfields ); + + ModBiblioMarc( $biblio, $biblionumber, $framework ); + if ( $verbose ) { + print "Changing MARC for biblio number $biblionumber.\n"; + } + else { + print "."; + } +} +print "\n"; + +if ( $update_frameworks ) { + print "Updating Koha to MARC mappings for seriestitle and volume\n"; + + # set new mappings for koha fields + $dbh->do( +"UPDATE marc_subfield_structure SET kohafield='seriestitle' + WHERE tagfield='490' AND tagsubfield='a'" + ); + $dbh->do( +"UPDATE marc_subfield_structure SET kohafield='volume' + WHERE tagfield='490' AND tagsubfield='v'" + ); + + # empty old koha fields + $dbh->do( +"UPDATE marc_subfield_structure SET kohafield='' + WHERE kohafield='seriestitle' AND tagfield='440' AND tagsubfield='a'" + ); + $dbh->do( +"UPDATE marc_subfield_structure SET kohafield='' + WHERE kohafield='volume' AND tagfield='440' AND tagsubfield='v'" + ); +} + +sub print_usage { + print <<_USAGE_; +$0: switch MARC21 440 tag and 490 tag contents + +Parameters: + -c Commit the changes to the marc records + + -m Also update the Koha field to MARC framework mappings for the + seriestitle and volume Koha fields. + + --help or -h show this message. + +_USAGE_ +} From 8cb3533ae69bf87a0ba5187abe711956165d3625 Mon Sep 17 00:00:00 2001 From: Michael Hafen Date: Thu, 21 Feb 2013 15:44:00 -0700 Subject: [PATCH 2/4] Bug 5608 - command-line tool to switch information in 440 and 490 tags With the MARC21 standard moving from the 440 tag to the 490, this tool is to help libraries make the move. It switches any information in 440 tags to 490 tags, and any information in 490 tags to 440 tags. That seemed like the best way to go to me. There is also an option to create 830 tags for any 44 information, like authorities, that can't be represented in the 490 tag. To Test: locate some biblios with 440 or 490 tags filled. run bin/migration_tools/switch_marc21_series_info.pl -c observe that the information in the biblios has switched 4xx tags. http://bugs.koha-community.org/show_bug.cgi?id=5608 Signed-off-by: Bernardo Gonzalez Kriegel Comment: Work as described. No errors. Signed-off-by: Paul Poulain Signed-off-by: Jared Camins-Esakov --- .../switch_marc21_series_info.pl | 129 ++++++++++++------ 1 file changed, 88 insertions(+), 41 deletions(-) diff --git a/misc/migration_tools/switch_marc21_series_info.pl b/misc/migration_tools/switch_marc21_series_info.pl index 28413a2e84..46b8120517 100755 --- a/misc/migration_tools/switch_marc21_series_info.pl +++ b/misc/migration_tools/switch_marc21_series_info.pl @@ -17,12 +17,14 @@ use C4::Context; use Getopt::Long; my $commit; +my $add_links; my $update_frameworks; my $show_help; my $verbose; my $result = GetOptions( 'c' => \$commit, - 'm' => \$update_frameworks, + 'l' => \$add_links, + 'f' => \$update_frameworks, 'h|help' => \$show_help, 'v' => \$verbose, ); @@ -53,83 +55,123 @@ unless ( $commit ) { else { print "There appears to be no series information to change\n"; } + print "Please run this again with the '-c' option to change the records\n"; exit 0; } print "Changing $num_records MARC records...\n"; +# MARC21 specific +my %fields = ( + '440' => { + 'a' => 'title', + 'n' => 'number', + 'p' => 'part', + 'v' => 'volume', + 'x' => 'issn', + '6' => 'link', + '8' => 'ln', + 'w' => 'control', + '0' => 'auth', + }, + '490' => { + 'a' => 'title', + 'v' => 'volume', + 'x' => 'issn', + '6' => 'link', + '8' => 'ln', + }, + ); + $bibs_sth->execute(); while ( my ( $biblionumber ) = $bibs_sth->fetchrow ) { my $framework = GetFrameworkCode( $biblionumber ) || ''; my ( @newfields ); - # MARC21 specific - my ( $series1_t, $series1_f ) = ( '440', 'a' ); - my ( $volume1_t, $volume1_f ) = ( '440', 'v' ); - my ( $number1_t, $number1_f ) = ( '440', 'n' ); - - my ( $series2_t, $series2_f ) = ( '490', 'a' ); - my ( $volume2_t, $volume2_f ) = ( '490', 'v' ); - # Get biblio marc my $biblio = GetMarcBiblio( $biblionumber ); - foreach my $field ( $biblio->field( $series1_t ) ) { + foreach my $field ( $biblio->field( '440' ) ) { my @newsubfields; - my @series1 = $field->subfield( $series1_f ); - my @volume1 = $field->subfield( $volume1_f ); - my @number1 = $field->subfield( $number1_f ); - my $i = 0; - foreach my $num ( @number1 ) { - $volume1[$i] .= " " if ( $volume1[$i] ); - $volume1[$i++] .= $num if ( $num ); - } + my @linksubfields; + my $has_links = '0'; + foreach my $subfield ( sort keys %{ $fields{'440'} } ) { + my @values = $field->subfield( $subfield ); - while ( @series1 || @volume1 ) { - if ( @series1 ) { - push @newsubfields, ( $series2_f, shift @series1 ); + if ( $add_links && @values ) { + if ( $subfield eq 'w' || $subfield eq '0' ) { + $has_links = '1'; + } + foreach my $v ( @values ) { + push @linksubfields, ( $subfield, $v ); + } } - if ( @volume1 ) { - push @newsubfields, ( $volume2_f, shift @volume1 ); + + if ( $subfield eq 'a' ) { + my @numbers = $field->subfield( 'n' ); + my @parts = $field->subfield( 'p' ); + my $i = 0; + while ( $i < @numbers || $i < @parts ) { + my @strings = grep {$_} ( $values[$i], $numbers[$i], $parts[$i] ); + $values[$i] = join ' ', @strings; + $i++; + } + } + + if ( $fields{'490'}{$subfield} ) { + foreach my $v ( @values ) { + push @newsubfields, ( $subfield, $v ); + } } } - my $new_field = MARC::Field->new( $series2_t, '', '', - @newsubfields ); + if ( $has_links && @linksubfields ) { + my $link_field = MARC::Field->new( + '830', + $field->indicator(1), $field->indicator(2), + @linksubfields + ); + push @newfields, $link_field; + } + + if ( @newsubfields ) { + my $new_field = MARC::Field->new( '490', $has_links, '', + @newsubfields ); + push @newfields, $new_field; + } $biblio->delete_fields( $field ); - push @newfields, $new_field; } - foreach my $field ( $biblio->field( $series2_t ) ) { + foreach my $field ( $biblio->field( '490' ) ) { my @newsubfields; - my @series2 = $field->subfield( $series2_f ); - my @volume2 = $field->subfield( $volume2_f ); + foreach my $subfield ( sort keys %{ $fields{'490'} } ) { + my @values = $field->subfield( $subfield ); - while ( @series2 || @volume2 ) { - if ( @series2 ) { - push @newsubfields, ( $series1_f, shift @series2 ); - } - if ( @volume2 ) { - push @newsubfields, ( $volume1_f, shift @volume2 ); + if ( $fields{'440'}{$subfield} ) { + foreach my $v ( @values ) { + push @newsubfields, ( $subfield, $v ); + } } } - my $new_field = MARC::Field->new( $series1_t, '', '', - @newsubfields ); + if ( @newsubfields ) { + my $new_field = MARC::Field->new( '440', '', '', + @newsubfields ); + push @newfields, $new_field; + } $biblio->delete_fields( $field ); - push @newfields, $new_field; } $biblio->insert_fields_ordered( @newfields ); - ModBiblioMarc( $biblio, $biblionumber, $framework ); if ( $verbose ) { print "Changing MARC for biblio number $biblionumber.\n"; } else { print "."; } + ModBiblioMarc( $biblio, $biblionumber, $framework ); } print "\n"; @@ -162,11 +204,16 @@ sub print_usage { $0: switch MARC21 440 tag and 490 tag contents Parameters: - -c Commit the changes to the marc records + -c Commit the changes to the marc records. - -m Also update the Koha field to MARC framework mappings for the + -l Add 830 tags with authority information from 440. Otherwise + this information will be ignored. + + -f Also update the Koha field to MARC framework mappings for the seriestitle and volume Koha fields. + -v Show more information as the records are being changed. + --help or -h show this message. _USAGE_ From b395ac0805db80837f009b278580970afdaa964a Mon Sep 17 00:00:00 2001 From: Michael Hafen Date: Mon, 25 Feb 2013 12:43:09 -0700 Subject: [PATCH 3/4] Add license statement to switch_series_info CLI script License and copyright statement added. Thanks to Bernardo Gonzalez Kriegel for reminding me about this. http://bugs.koha-community.org/show_bug.cgi?id=5608 Signed-off-by: Bernardo Gonzalez Kriegel Comment: add license information. No errors. Signed-off-by: Paul Poulain Signed-off-by: Jared Camins-Esakov --- .../switch_marc21_series_info.pl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/misc/migration_tools/switch_marc21_series_info.pl b/misc/migration_tools/switch_marc21_series_info.pl index 46b8120517..9f67e026c7 100755 --- a/misc/migration_tools/switch_marc21_series_info.pl +++ b/misc/migration_tools/switch_marc21_series_info.pl @@ -1,5 +1,22 @@ #!/usr/bin/perl +# Copyright 2013 Michael Hafen +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + use strict; use warnings; From be82a5f94208a6f41e033398c53fc3e9d0f80e62 Mon Sep 17 00:00:00 2001 From: Paul Poulain Date: Thu, 21 Mar 2013 16:55:07 +0100 Subject: [PATCH 4/4] bug 5608 follow-up: exit immediately if UNIMARC Signed-off-by: Paul Poulain Signed-off-by: Jared Camins-Esakov --- misc/migration_tools/switch_marc21_series_info.pl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/misc/migration_tools/switch_marc21_series_info.pl b/misc/migration_tools/switch_marc21_series_info.pl index 9f67e026c7..cfd204b57d 100755 --- a/misc/migration_tools/switch_marc21_series_info.pl +++ b/misc/migration_tools/switch_marc21_series_info.pl @@ -46,6 +46,11 @@ my $result = GetOptions( 'v' => \$verbose, ); +# warn and exit if we're running UNIMARC +if (C4::Context->preference('MARCFLAVOUR') eq 'UNIMARC') { + print "This script is useless when you're running UNIMARC\n"; + exit 0; +} if ( ! $result || $show_help ) { print_usage(); exit 0;