1 package Koha
::SimpleMARC
;
3 # Copyright 2009 Kyle M. Hall <kyle.m.hall@gmail.com>
11 our @ISA = qw(Exporter);
12 our %EXPORT_TAGS = ( 'all' => [ qw(
16 our @EXPORT_OK = ( @
{ $EXPORT_TAGS{'all'} } );
22 copy_and_replace_field
29 our $VERSION = '0.01';
35 SimpleMARC - Perl module for making simple MARC record alterations.
43 SimpleMARC is designed to make writing scripts
44 to modify MARC records simple and easy.
46 Every function in the modules requires a
47 MARC::Record object as its first parameter.
51 Kyle Hall <lt>kyle.m.hall@gmail.com<gt>
53 =head1 COPYRIGHT AND LICENSE
55 Copyright (C) 2009 by Kyle Hall
57 This library is free software; you can redistribute it and/or modify
58 it under the same terms as Perl itself, either Perl version 5.8.7 or,
59 at your option, any later version of Perl 5 you may have available.
65 copy_field( $record, $fromFieldName, $fromSubfieldName, $toFieldName, $toSubfieldName[, $regex[, $n ] ] );
67 Copies a value from one field to another. If a regular expression ( $regex ) is supplied,
68 the value will be transformed by the given regex before being copied into the new field.
69 Example: $regex = { search => 'Old Text', replace => 'Replacement Text', modifiers => 'g' };
71 If $n is passed, copy_field will only copy the Nth field of the list of fields.
72 E.g. $n = 1 will only use the first field's value, $n = 2 will use only the 2nd field's value.
78 my $record = $params->{record
};
79 my $fromFieldName = $params->{from_field
};
80 my $fromSubfieldName = $params->{from_subfield
};
81 my $toFieldName = $params->{to_field
};
82 my $toSubfieldName = $params->{to_subfield
};
83 my $regex = $params->{regex
};
84 my $field_numbers = $params->{field_numbers
} // [];
86 if ( ! ( $record && $fromFieldName && $toFieldName ) ) { return; }
89 if ( not $fromSubfieldName
90 or $fromSubfieldName eq ''
91 or not $toSubfieldName
92 or $toSubfieldName eq '' ) {
95 from_field
=> $fromFieldName,
96 to_field
=> $toFieldName,
98 field_numbers
=> $field_numbers,
105 from_field
=> $fromFieldName,
106 from_subfield
=> $fromSubfieldName,
107 to_field
=> $toFieldName,
108 to_subfield
=> $toSubfieldName,
110 field_numbers
=> $field_numbers,
117 sub copy_and_replace_field
{
119 my $record = $params->{record
};
120 my $fromFieldName = $params->{from_field
};
121 my $fromSubfieldName = $params->{from_subfield
};
122 my $toFieldName = $params->{to_field
};
123 my $toSubfieldName = $params->{to_subfield
};
124 my $regex = $params->{regex
};
125 my $field_numbers = $params->{field_numbers
} // [];
127 if ( ! ( $record && $fromFieldName && $toFieldName ) ) { return; }
130 if ( not $fromSubfieldName or $fromSubfieldName eq ''
131 or not $toSubfieldName or $toSubfieldName eq ''
135 from_field
=> $fromFieldName,
136 to_field
=> $toFieldName,
138 field_numbers
=> $field_numbers,
145 from_field
=> $fromFieldName,
146 from_subfield
=> $fromSubfieldName,
147 to_field
=> $toFieldName,
148 to_subfield
=> $toSubfieldName,
150 field_numbers
=> $field_numbers,
159 my $record = $params->{record
};
160 my $fieldName = $params->{field
};
161 my $subfieldName = $params->{subfield
};
162 my @values = @
{ $params->{values} };
163 my $field_numbers = $params->{field_numbers
} // [];
165 if ( ! ( $record && $fieldName ) ) { return; }
167 if ( not $subfieldName or $subfieldName eq '' ) {
168 # FIXME I'm not sure the actual implementation is correct.
169 die "This action is not implemented yet";
170 #_update_field({ record => $record, field => $fieldName, values => \@values });
172 _update_subfield
({ record
=> $record, field
=> $fieldName, subfield
=> $subfieldName, values => \
@values, field_numbers
=> $field_numbers });
178 my $record = $params->{record
};
179 my $fieldName = $params->{field
};
180 my @values = @
{ $params->{values} };
183 if ( my @fields = $record->field( $fieldName ) ) {
184 @values = ($values[0]) x
scalar( @fields )
186 foreach my $field ( @fields ) {
187 $field->update( $values[$i++] );
190 ## Field does not exists, create it
191 if ( $fieldName < 10 ) {
192 foreach my $value ( @values ) {
193 my $field = MARC
::Field
->new( $fieldName, $value );
194 $record->append_fields( $field );
197 warn "Invalid operation, trying to add a new field without subfield";
202 sub _update_subfield
{
204 my $record = $params->{record
};
205 my $fieldName = $params->{field
};
206 my $subfieldName = $params->{subfield
};
207 my @values = @
{ $params->{values} };
208 my $dont_erase = $params->{dont_erase
};
209 my $field_numbers = $params->{field_numbers
} // [];
212 my @fields = $record->field( $fieldName );
214 if ( @
$field_numbers ) {
215 @fields = map { $_ <= @fields ?
$fields[ $_ - 1 ] : () } @
$field_numbers;
219 unless ( $dont_erase ) {
220 @values = ($values[0]) x
scalar( @fields )
222 foreach my $field ( @fields ) {
223 $field->update( "$subfieldName" => $values[$i++] );
226 if ( $i <= scalar ( @values ) - 1 ) {
227 foreach my $field ( @fields ) {
228 foreach my $j ( $i .. scalar( @values ) - 1) {
229 $field->add_subfields( "$subfieldName" => $values[$j] );
234 ## Field does not exist, create it.
235 foreach my $value ( @values ) {
236 my $field = MARC
::Field
->new( $fieldName, '', '', "$subfieldName" => $values[$i++] );
237 $record->append_fields( $field );
244 my @values = read_field( $record, $fieldName[, $subfieldName, [, $n ] ] );
246 Returns an array of field values for the given field and subfield
248 If $n is given, it will return only the $nth value of the array.
249 E.g. If $n = 1, it return the 1st value, if $n = 3, it will return the 3rd value.
255 my $record = $params->{record
};
256 my $fieldName = $params->{field
};
257 my $subfieldName = $params->{subfield
};
258 my $field_numbers = $params->{field_numbers
} // [];
260 if ( not $subfieldName or $subfieldName eq '' ) {
261 _read_field
({ record
=> $record, field
=> $fieldName, field_numbers
=> $field_numbers });
263 _read_subfield
({ record
=> $record, field
=> $fieldName, subfield
=> $subfieldName, field_numbers
=> $field_numbers });
269 my $record = $params->{record
};
270 my $fieldName = $params->{field
};
271 my $field_numbers = $params->{field_numbers
} // [];
273 my @fields = $record->field( $fieldName );
275 return unless @fields;
277 return map { $_->data() } @fields
281 if ( @
$field_numbers ) {
282 for my $field_number ( @
$field_numbers ) {
283 if ( $field_number <= scalar( @fields ) ) {
284 for my $sf ( $fields[$field_number - 1]->subfields ) {
285 push @values, $sf->[1];
290 foreach my $field ( @fields ) {
291 for my $sf ( $field->subfields ) {
292 push @values, $sf->[1];
302 my $record = $params->{record
};
303 my $fieldName = $params->{field
};
304 my $subfieldName = $params->{subfield
};
305 my $field_numbers = $params->{field_numbers
} // [];
307 my @fields = $record->field( $fieldName );
309 return unless @fields;
312 foreach my $field ( @fields ) {
313 my @sf = $field->subfield( $subfieldName );
314 push( @values, @sf );
317 if ( @values and @
$field_numbers ) {
318 @values = map { $_ <= @values ?
$values[ $_ - 1 ] : () } @
$field_numbers;
326 @field_numbers = field_exists( $record, $fieldName[, $subfieldName ]);
328 Returns the field numbers or an empty array.
334 my $record = $params->{record
};
335 my $fieldName = $params->{field
};
336 my $subfieldName = $params->{subfield
};
338 if ( ! $record ) { return; }
340 my @field_numbers = ();
341 my $current_field_number = 1;
342 for my $field ( $record->field( $fieldName ) ) {
343 if ( $subfieldName ) {
344 push @field_numbers, $current_field_number
345 if $field->subfield( $subfieldName );
347 push @field_numbers, $current_field_number;
349 $current_field_number++;
352 return \
@field_numbers;
357 $bool = field_equals( $record, $value, $fieldName[, $subfieldName[, $regex ] ]);
359 Returns true if the field equals the given value, false otherwise.
361 If a regular expression ( $regex ) is supplied, the value will be compared using
362 the given regex. Example: $regex = 'sought_text'
368 my $record = $params->{record
};
369 my $value = $params->{value
};
370 my $fieldName = $params->{field
};
371 my $subfieldName = $params->{subfield
};
372 my $is_regex = $params->{is_regex
};
374 if ( ! $record ) { return; }
376 my @field_numbers = ();
377 my $current_field_number = 1;
378 FIELDS
: for my $field ( $record->field( $fieldName ) ) {
379 my @subfield_values = $subfieldName
380 ?
$field->subfield( $subfieldName )
381 : map { $_->[1] } $field->subfields;
383 SUBFIELDS
: for my $subfield_value ( @subfield_values ) {
386 $is_regex and $subfield_value =~ m/$value/
388 $subfield_value eq $value
391 push @field_numbers, $current_field_number;
395 $current_field_number++;
398 return \
@field_numbers;
403 move_field( $record, $fromFieldName, $fromSubfieldName, $toFieldName, $toSubfieldName[, $regex [, $n ] ] );
405 Moves a value from one field to another. If a regular expression ( $regex ) is supplied,
406 the value will be transformed by the given regex before being moved into the new field.
407 Example: $regex = 's/Old Text/Replacement Text/'
409 If $n is passed, only the Nth field will be moved. $n = 1
410 will move the first repeatable field, $n = 3 will move the third.
416 my $record = $params->{record
};
417 my $fromFieldName = $params->{from_field
};
418 my $fromSubfieldName = $params->{from_subfield
};
419 my $toFieldName = $params->{to_field
};
420 my $toSubfieldName = $params->{to_subfield
};
421 my $regex = $params->{regex
};
422 my $field_numbers = $params->{field_numbers
} // [];
424 if ( not $fromSubfieldName
425 or $fromSubfieldName eq ''
426 or not $toSubfieldName
427 or $toSubfieldName eq '' ) {
430 from_field
=> $fromFieldName,
431 to_field
=> $toFieldName,
433 field_numbers
=> $field_numbers,
440 from_field
=> $fromFieldName,
441 from_subfield
=> $fromSubfieldName,
442 to_field
=> $toFieldName,
443 to_subfield
=> $toSubfieldName,
445 field_numbers
=> $field_numbers,
454 _delete_field( $record, $fieldName[, $subfieldName [, $n ] ] );
456 Deletes the given field.
458 If $n is passed, only the Nth field will be deleted. $n = 1
459 will delete the first repeatable field, $n = 3 will delete the third.
465 my $record = $params->{record
};
466 my $fieldName = $params->{field
};
467 my $subfieldName = $params->{subfield
};
468 my $field_numbers = $params->{field_numbers
} // [];
470 if ( not $subfieldName or $subfieldName eq '' ) {
471 _delete_field
({ record
=> $record, field
=> $fieldName, field_numbers
=> $field_numbers });
473 _delete_subfield
({ record
=> $record, field
=> $fieldName, subfield
=> $subfieldName, field_numbers
=> $field_numbers });
479 my $record = $params->{record
};
480 my $fieldName = $params->{field
};
481 my $field_numbers = $params->{field_numbers
} // [];
483 my @fields = $record->field( $fieldName );
485 if ( @
$field_numbers ) {
486 @fields = map { $_ <= @fields ?
$fields[ $_ - 1 ] : () } @
$field_numbers;
488 foreach my $field ( @fields ) {
489 $record->delete_field( $field );
493 sub _delete_subfield
{
495 my $record = $params->{record
};
496 my $fieldName = $params->{field
};
497 my $subfieldName = $params->{subfield
};
498 my $field_numbers = $params->{field_numbers
} // [];
500 my @fields = $record->field( $fieldName );
502 if ( @
$field_numbers ) {
503 @fields = map { $_ <= @fields ?
$fields[ $_ - 1 ] : () } @
$field_numbers;
506 foreach my $field ( @fields ) {
507 $field->delete_subfield( code
=> $subfieldName );
512 sub _copy_move_field
{
514 my $record = $params->{record
};
515 my $fromFieldName = $params->{from_field
};
516 my $toFieldName = $params->{to_field
};
517 my $regex = $params->{regex
};
518 my $field_numbers = $params->{field_numbers
} // [];
519 my $action = $params->{action
} || 'copy';
521 my @from_fields = $record->field( $fromFieldName );
522 if ( @
$field_numbers ) {
523 @from_fields = map { $_ <= @from_fields ?
$from_fields[ $_ - 1 ] : () } @
$field_numbers;
527 for my $from_field ( @from_fields ) {
528 my $new_field = $from_field->clone;
529 $new_field->{_tag
} = $toFieldName; # Should be replaced by set_tag, introduced by MARC::Field 2.0.4
530 if ( $regex and $regex->{search
} ) {
531 for my $subfield ( $new_field->subfields ) {
532 my $value = $subfield->[1];
533 ( $value ) = _modify_values
({ values => [ $value ], regex
=> $regex });
534 $new_field->update( $subfield->[0], $value );
537 if ( $action eq 'move' ) {
538 $record->delete_field( $from_field )
540 elsif ( $action eq 'replace' ) {
541 my @to_fields = $record->field( $toFieldName );
543 $record->delete_field( $to_fields[0] );
546 push @new_fields, $new_field;
548 $record->append_fields( @new_fields );
551 sub _copy_move_subfield
{
553 my $record = $params->{record
};
554 my $fromFieldName = $params->{from_field
};
555 my $fromSubfieldName = $params->{from_subfield
};
556 my $toFieldName = $params->{to_field
};
557 my $toSubfieldName = $params->{to_subfield
};
558 my $regex = $params->{regex
};
559 my $field_numbers = $params->{field_numbers
} // [];
560 my $action = $params->{action
} || 'copy';
562 my @values = read_field
({ record
=> $record, field
=> $fromFieldName, subfield
=> $fromSubfieldName });
563 if ( @
$field_numbers ) {
564 @values = map { $_ <= @values ?
$values[ $_ - 1 ] : () } @
$field_numbers;
566 _modify_values
({ values => \
@values, regex
=> $regex });
567 my $dont_erase = $action eq 'copy' ?
1 : 0;
568 _update_subfield
({ record
=> $record, field
=> $toFieldName, subfield
=> $toSubfieldName, values => \
@values, dont_erase
=> $dont_erase });
570 # And delete if it's a move
571 if ( $action eq 'move' ) {
574 field
=> $fromFieldName,
575 subfield
=> $fromSubfieldName,
576 field_numbers
=> $field_numbers,
583 my $values = $params->{values};
584 my $regex = $params->{regex
};
586 if ( $regex and $regex->{search
} ) {
587 $regex->{modifiers
} //= q
||;
588 my @available_modifiers = qw( i g );
590 for my $modifier ( split //, $regex->{modifiers
} ) {
591 $modifiers .= $modifier
592 if grep {/$modifier/} @available_modifiers;
594 foreach my $value ( @
$values ) {
595 if ( $modifiers =~ m/^(ig|gi)$/ ) {
596 $value =~ s/$regex->{search}/$regex->{replace}/ig;
598 elsif ( $modifiers eq 'i' ) {
599 $value =~ s/$regex->{search}/$regex->{replace}/i;
601 elsif ( $modifiers eq 'g' ) {
602 $value =~ s/$regex->{search}/$regex->{replace}/g;
605 $value =~ s/$regex->{search}/$regex->{replace}/;