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'} } );
28 our $VERSION = '0.01';
34 SimpleMARC - Perl module for making simple MARC record alterations.
42 SimpleMARC is designed to make writing scripts
43 to modify MARC records simple and easy.
45 Every function in the modules requires a
46 MARC::Record object as its first parameter.
50 Kyle Hall <lt>kyle.m.hall@gmail.com<gt>
52 =head1 COPYRIGHT AND LICENSE
54 Copyright (C) 2009 by Kyle Hall
56 This library is free software; you can redistribute it and/or modify
57 it under the same terms as Perl itself, either Perl version 5.8.7 or,
58 at your option, any later version of Perl 5 you may have available.
64 copy_field( $record, $fromFieldName, $fromSubfieldName, $toFieldName, $toSubfieldName[, $regex[, $n ] ] );
66 Copies a value from one field to another. If a regular expression ( $regex ) is supplied,
67 the value will be transformed by the given regex before being copied into the new field.
68 Example: $regex = { search => 'Old Text', replace => 'Replacement Text', modifiers => 'g' };
70 If $n is passed, copy_field will only copy the Nth field of the list of fields.
71 E.g. $n = 1 will only use the first field's value, $n = 2 will use only the 2nd field's value.
77 my $record = $params->{record
};
78 my $fromFieldName = $params->{from_field
};
79 my $fromSubfieldName = $params->{from_subfield
};
80 my $toFieldName = $params->{to_field
};
81 my $toSubfieldName = $params->{to_subfield
};
82 my $regex = $params->{regex
};
83 my $field_numbers = $params->{field_numbers
} // [];
85 if ( ! ( $record && $fromFieldName && $toFieldName ) ) { return; }
88 if ( not $fromSubfieldName or $fromSubfieldName eq ''
89 or not $toSubfieldName or $toSubfieldName eq ''
93 from_field
=> $fromFieldName,
94 to_field
=> $toFieldName,
96 field_numbers
=> $field_numbers,
101 from_field
=> $fromFieldName,
102 from_subfield
=> $fromSubfieldName,
103 to_field
=> $toFieldName,
104 to_subfield
=> $toSubfieldName,
106 field_numbers
=> $field_numbers,
114 my $record = $params->{record
};
115 my $fromFieldName = $params->{from_field
};
116 my $toFieldName = $params->{to_field
};
117 my $regex = $params->{regex
};
118 my $field_numbers = $params->{field_numbers
} // [];
122 from_field
=> $fromFieldName,
123 to_field
=> $toFieldName,
125 field_numbers
=> $field_numbers,
131 my $record = $params->{record
};
132 my $fromFieldName = $params->{from_field
};
133 my $fromSubfieldName = $params->{from_subfield
};
134 my $toFieldName = $params->{to_field
};
135 my $toSubfieldName = $params->{to_subfield
};
136 my $regex = $params->{regex
};
137 my $field_numbers = $params->{field_numbers
} // [];
139 my @values = read_field
({ record
=> $record, field
=> $fromFieldName, subfield
=> $fromSubfieldName });
140 if ( @
$field_numbers ) {
141 @values = map { $_ <= @values ?
$values[ $_ - 1 ] : () } @
$field_numbers;
143 _modify_values
({ values => \
@values, regex
=> $regex });
145 update_field
({ record
=> $record, field
=> $toFieldName, subfield
=> $toSubfieldName, values => \
@values });
150 my $record = $params->{record
};
151 my $fieldName = $params->{field
};
152 my $subfieldName = $params->{subfield
};
153 my @values = @
{ $params->{values} };
154 my $field_numbers = $params->{field_numbers
} // [];
156 if ( ! ( $record && $fieldName ) ) { return; }
158 if ( not $subfieldName or $subfieldName eq '' ) {
159 # FIXME I'm not sure the actual implementation is correct.
160 die "This action is not implemented yet";
161 #_update_field({ record => $record, field => $fieldName, values => \@values });
163 _update_subfield
({ record
=> $record, field
=> $fieldName, subfield
=> $subfieldName, values => \
@values, field_numbers
=> $field_numbers });
169 my $record = $params->{record
};
170 my $fieldName = $params->{field
};
171 my @values = @
{ $params->{values} };
174 if ( my @fields = $record->field( $fieldName ) ) {
175 @values = ($values[0]) x
scalar( @fields )
177 foreach my $field ( @fields ) {
178 $field->update( $values[$i++] );
181 ## Field does not exists, create it
182 if ( $fieldName < 10 ) {
183 foreach my $value ( @values ) {
184 my $field = MARC
::Field
->new( $fieldName, $value );
185 $record->append_fields( $field );
188 warn "Invalid operation, trying to add a new field without subfield";
193 sub _update_subfield
{
195 my $record = $params->{record
};
196 my $fieldName = $params->{field
};
197 my $subfieldName = $params->{subfield
};
198 my @values = @
{ $params->{values} };
199 my $dont_erase = $params->{dont_erase
};
200 my $field_numbers = $params->{field_numbers
} // [];
203 my @fields = $record->field( $fieldName );
205 if ( @
$field_numbers ) {
206 @fields = map { $_ <= @fields ?
$fields[ $_ - 1 ] : () } @
$field_numbers;
210 unless ( $dont_erase ) {
211 @values = ($values[0]) x
scalar( @fields )
213 foreach my $field ( @fields ) {
214 $field->update( "$subfieldName" => $values[$i++] );
217 if ( $i <= scalar ( @values ) - 1 ) {
218 foreach my $field ( @fields ) {
219 foreach my $j ( $i .. scalar( @values ) - 1) {
220 $field->add_subfields( "$subfieldName" => $values[$j] );
225 ## Field does not exist, create it.
226 foreach my $value ( @values ) {
227 my $field = MARC
::Field
->new( $fieldName, '', '', "$subfieldName" => $values[$i++] );
228 $record->append_fields( $field );
235 my @values = read_field( $record, $fieldName[, $subfieldName, [, $n ] ] );
237 Returns an array of field values for the given field and subfield
239 If $n is given, it will return only the $nth value of the array.
240 E.g. If $n = 1, it return the 1st value, if $n = 3, it will return the 3rd value.
246 my $record = $params->{record
};
247 my $fieldName = $params->{field
};
248 my $subfieldName = $params->{subfield
};
249 my $field_numbers = $params->{field_numbers
} // [];
251 if ( not $subfieldName or $subfieldName eq '' ) {
252 _read_field
({ record
=> $record, field
=> $fieldName, field_numbers
=> $field_numbers });
254 _read_subfield
({ record
=> $record, field
=> $fieldName, subfield
=> $subfieldName, field_numbers
=> $field_numbers });
260 my $record = $params->{record
};
261 my $fieldName = $params->{field
};
262 my $field_numbers = $params->{field_numbers
} // [];
264 my @fields = $record->field( $fieldName );
266 return unless @fields;
268 return map { $_->data() } @fields
272 if ( @
$field_numbers ) {
273 for my $field_number ( @
$field_numbers ) {
274 if ( $field_number <= scalar( @fields ) ) {
275 for my $sf ( $fields[$field_number - 1]->subfields ) {
276 push @values, $sf->[1];
281 foreach my $field ( @fields ) {
282 for my $sf ( $field->subfields ) {
283 push @values, $sf->[1];
293 my $record = $params->{record
};
294 my $fieldName = $params->{field
};
295 my $subfieldName = $params->{subfield
};
296 my $field_numbers = $params->{field_numbers
} // [];
298 my @fields = $record->field( $fieldName );
300 return unless @fields;
303 foreach my $field ( @fields ) {
304 my @sf = $field->subfield( $subfieldName );
305 push( @values, @sf );
308 if ( @values and @
$field_numbers ) {
309 @values = map { $_ <= @values ?
$values[ $_ - 1 ] : () } @
$field_numbers;
317 @field_numbers = field_exists( $record, $fieldName[, $subfieldName ]);
319 Returns the field numbers or an empty array.
325 my $record = $params->{record
};
326 my $fieldName = $params->{field
};
327 my $subfieldName = $params->{subfield
};
329 if ( ! $record ) { return; }
331 my @field_numbers = ();
332 my $current_field_number = 1;
333 for my $field ( $record->field( $fieldName ) ) {
334 if ( $subfieldName ) {
335 push @field_numbers, $current_field_number
336 if $field->subfield( $subfieldName );
338 push @field_numbers, $current_field_number;
340 $current_field_number++;
343 return \
@field_numbers;
348 $bool = field_equals( $record, $value, $fieldName[, $subfieldName[, $regex ] ]);
350 Returns true if the field equals the given value, false otherwise.
352 If a regular expression ( $regex ) is supplied, the value will be compared using
353 the given regex. Example: $regex = 'sought_text'
359 my $record = $params->{record
};
360 my $value = $params->{value
};
361 my $fieldName = $params->{field
};
362 my $subfieldName = $params->{subfield
};
363 my $is_regex = $params->{is_regex
};
365 if ( ! $record ) { return; }
367 my @field_numbers = ();
368 my $current_field_number = 1;
369 FIELDS
: for my $field ( $record->field( $fieldName ) ) {
370 my @subfield_values = $subfieldName
371 ?
$field->subfield( $subfieldName )
372 : map { $_->[1] } $field->subfields;
374 SUBFIELDS
: for my $subfield_value ( @subfield_values ) {
377 $is_regex and $subfield_value =~ m/$value/
379 $subfield_value eq $value
382 push @field_numbers, $current_field_number;
386 $current_field_number++;
389 return \
@field_numbers;
394 move_field( $record, $fromFieldName, $fromSubfieldName, $toFieldName, $toSubfieldName[, $regex [, $n ] ] );
396 Moves a value from one field to another. If a regular expression ( $regex ) is supplied,
397 the value will be transformed by the given regex before being moved into the new field.
398 Example: $regex = 's/Old Text/Replacement Text/'
400 If $n is passed, only the Nth field will be moved. $n = 1
401 will move the first repeatable field, $n = 3 will move the third.
407 my $record = $params->{record
};
408 my $fromFieldName = $params->{from_field
};
409 my $fromSubfieldName = $params->{from_subfield
};
410 my $toFieldName = $params->{to_field
};
411 my $toSubfieldName = $params->{to_subfield
};
412 my $regex = $params->{regex
};
413 my $field_numbers = $params->{field_numbers
} // [];
415 if ( not $fromSubfieldName or $fromSubfieldName eq ''
416 or not $toSubfieldName or $toSubfieldName eq ''
420 from_field
=> $fromFieldName,
421 to_field
=> $toFieldName,
423 field_numbers
=> $field_numbers,
428 from_field
=> $fromFieldName,
429 from_subfield
=> $fromSubfieldName,
430 to_field
=> $toFieldName,
431 to_subfield
=> $toSubfieldName,
433 field_numbers
=> $field_numbers,
440 my $record = $params->{record
};
441 my $fromFieldName = $params->{from_field
};
442 my $toFieldName = $params->{to_field
};
443 my $regex = $params->{regex
};
444 my $field_numbers = $params->{field_numbers
} // [];
448 from_field
=> $fromFieldName,
449 to_field
=> $toFieldName,
451 field_numbers
=> $field_numbers,
458 my $record = $params->{record
};
459 my $fromFieldName = $params->{from_field
};
460 my $fromSubfieldName = $params->{from_subfield
};
461 my $toFieldName = $params->{to_field
};
462 my $toSubfieldName = $params->{to_subfield
};
463 my $regex = $params->{regex
};
464 my $field_numbers = $params->{field_numbers
} // [];
467 my @values = read_field
({ record
=> $record, field
=> $fromFieldName, subfield
=> $fromSubfieldName });
468 if ( @
$field_numbers ) {
469 @values = map { $_ <= @values ?
$values[ $_ - 1 ] : () } @
$field_numbers;
471 _modify_values
({ values => \
@values, regex
=> $regex });
472 _update_subfield
({ record
=> $record, field
=> $toFieldName, subfield
=> $toSubfieldName, dont_erase
=> 1, values => \
@values });
477 field
=> $fromFieldName,
478 subfield
=> $fromSubfieldName,
479 field_numbers
=> $field_numbers,
485 _delete_field( $record, $fieldName[, $subfieldName [, $n ] ] );
487 Deletes the given field.
489 If $n is passed, only the Nth field will be deleted. $n = 1
490 will delete the first repeatable field, $n = 3 will delete the third.
496 my $record = $params->{record
};
497 my $fieldName = $params->{field
};
498 my $subfieldName = $params->{subfield
};
499 my $field_numbers = $params->{field_numbers
} // [];
501 if ( not $subfieldName or $subfieldName eq '' ) {
502 _delete_field
({ record
=> $record, field
=> $fieldName, field_numbers
=> $field_numbers });
504 _delete_subfield
({ record
=> $record, field
=> $fieldName, subfield
=> $subfieldName, field_numbers
=> $field_numbers });
510 my $record = $params->{record
};
511 my $fieldName = $params->{field
};
512 my $field_numbers = $params->{field_numbers
} // [];
514 my @fields = $record->field( $fieldName );
516 if ( @
$field_numbers ) {
517 @fields = map { $_ <= @fields ?
$fields[ $_ - 1 ] : () } @
$field_numbers;
519 foreach my $field ( @fields ) {
520 $record->delete_field( $field );
524 sub _delete_subfield
{
526 my $record = $params->{record
};
527 my $fieldName = $params->{field
};
528 my $subfieldName = $params->{subfield
};
529 my $field_numbers = $params->{field_numbers
} // [];
531 my @fields = $record->field( $fieldName );
533 if ( @
$field_numbers ) {
534 @fields = map { $_ <= @fields ?
$fields[ $_ - 1 ] : () } @
$field_numbers;
537 foreach my $field ( @fields ) {
538 $field->delete_subfield( code
=> $subfieldName );
543 sub _copy_move_field
{
545 my $record = $params->{record
};
546 my $fromFieldName = $params->{from_field
};
547 my $toFieldName = $params->{to_field
};
548 my $regex = $params->{regex
};
549 my $field_numbers = $params->{field_numbers
} // [];
550 my $action = $params->{action
} || 'copy';
552 my @fields = $record->field( $fromFieldName );
553 if ( @
$field_numbers ) {
554 @fields = map { $_ <= @fields ?
$fields[ $_ - 1 ] : () } @
$field_numbers;
557 for my $field ( @fields ) {
558 my $new_field = $field->clone;
559 $new_field->{_tag
} = $toFieldName; # Should be replaced by set_tag, introduced by MARC::Field 2.0.4
560 if ( $regex and $regex->{search
} ) {
561 for my $subfield ( $new_field->subfields ) {
562 my $value = $subfield->[1];
563 ( $value ) = _modify_values
({ values => [ $value ], regex
=> $regex });
564 $new_field->update( $subfield->[0], $value );
567 $record->append_fields( $new_field );
568 $record->delete_field( $field )
569 if $action eq 'move';
575 my $values = $params->{values};
576 my $regex = $params->{regex
};
578 if ( $regex and $regex->{search
} ) {
579 $regex->{modifiers
} //= q
||;
580 my @available_modifiers = qw( i g );
582 for my $modifier ( split //, $regex->{modifiers
} ) {
583 $modifiers .= $modifier
584 if grep {/$modifier/} @available_modifiers;
586 foreach my $value ( @
$values ) {
587 if ( $modifiers =~ m/^(ig|gi)$/ ) {
588 $value =~ s/$regex->{search}/$regex->{replace}/ig;
590 elsif ( $modifiers eq 'i' ) {
591 $value =~ s/$regex->{search}/$regex->{replace}/i;
593 elsif ( $modifiers eq 'g' ) {
594 $value =~ s/$regex->{search}/$regex->{replace}/g;
597 $value =~ s/$regex->{search}/$regex->{replace}/;