Lines 41-46
use MARC::File::XML;
Link Here
|
41 |
use MIME::Base64; |
41 |
use MIME::Base64; |
42 |
use Encode qw(encode); |
42 |
use Encode qw(encode); |
43 |
use Business::ISBN; |
43 |
use Business::ISBN; |
|
|
44 |
use Scalar::Util qw(looks_like_number); |
44 |
|
45 |
|
45 |
__PACKAGE__->mk_ro_accessors(qw( index )); |
46 |
__PACKAGE__->mk_ro_accessors(qw( index )); |
46 |
__PACKAGE__->mk_accessors(qw( sort_fields )); |
47 |
__PACKAGE__->mk_accessors(qw( sort_fields )); |
Lines 346-352
sub sort_fields {
Link Here
|
346 |
return $self->_sort_fields_accessor(); |
347 |
return $self->_sort_fields_accessor(); |
347 |
} |
348 |
} |
348 |
|
349 |
|
349 |
=head2 _process_mappings($mappings, $data, $record_document, $altscript) |
350 |
=head2 _process_mappings($mappings, $data, $record_document, $meta) |
350 |
|
351 |
|
351 |
$self->_process_mappings($mappings, $marc_field_data, $record_document, 0) |
352 |
$self->_process_mappings($mappings, $marc_field_data, $record_document, 0) |
352 |
|
353 |
|
Lines 374-396
The source data from a MARC record field.
Link Here
|
374 |
Hashref representing the Elasticsearch document on which mappings should be |
375 |
Hashref representing the Elasticsearch document on which mappings should be |
375 |
applied. |
376 |
applied. |
376 |
|
377 |
|
377 |
=item C<$altscript> |
378 |
=item C<$meta> |
378 |
|
379 |
|
379 |
A boolean value indicating whether an alternate script presentation is being |
380 |
A hashref containing metadata useful for enforcing per mapping rules. For |
|
|
381 |
example for providing extra context for mapping options, or treating mapping |
382 |
targets differently depending on type (sort, search, facet etc). Combining |
383 |
this metadata with the mapping options and metadata allows us to mutate the |
384 |
data per mapping, or even replace it with other data retrieved from the |
385 |
metadata context. |
386 |
|
387 |
Current properties are: |
388 |
|
389 |
C<altscript>: A boolean value indicating whether an alternate script presentation is being |
380 |
processed. |
390 |
processed. |
381 |
|
391 |
|
|
|
392 |
C<data_source>: The source of the $<data> argument. Possible values are: 'leader', 'control_field', |
393 |
'subfield' or 'subfields_group'. |
394 |
|
395 |
C<code>: The code of the subfield C<$data> was retrieved, if C<data_source> is 'subfield'. |
396 |
|
397 |
C<codes>: Subfield codes of the subfields group from which C<$data> was retrieved, if C<data_source> |
398 |
is 'subfields_group'. |
399 |
|
400 |
C<field>: The original marc field object. |
401 |
|
382 |
=back |
402 |
=back |
383 |
|
403 |
|
384 |
=cut |
404 |
=cut |
385 |
|
405 |
|
386 |
sub _process_mappings { |
406 |
sub _process_mappings { |
387 |
my ($_self, $mappings, $data, $record_document, $altscript) = @_; |
407 |
my ($_self, $mappings, $data, $record_document, $meta) = @_; |
388 |
foreach my $mapping (@{$mappings}) { |
408 |
foreach my $mapping (@{$mappings}) { |
389 |
my ($target, $options) = @{$mapping}; |
409 |
my ($target, $options) = @{$mapping}; |
390 |
|
410 |
|
391 |
# Don't process sort fields for alternate scripts |
411 |
# Don't process sort fields for alternate scripts |
392 |
my $sort = $target =~ /__sort$/; |
412 |
my $sort = $target =~ /__sort$/; |
393 |
if ($sort && $altscript) { |
413 |
if ($sort && $meta->{altscript}) { |
394 |
next; |
414 |
next; |
395 |
} |
415 |
} |
396 |
|
416 |
|
Lines 411-416
sub _process_mappings {
Link Here
|
411 |
$options->{property} => $_data |
431 |
$options->{property} => $_data |
412 |
} |
432 |
} |
413 |
} |
433 |
} |
|
|
434 |
if (defined $options->{nonfiling_characters_indicator}) { |
435 |
my $nonfiling_chars = $meta->{field}->indicator($options->{nonfiling_characters_indicator}); |
436 |
$nonfiling_chars = looks_like_number($nonfiling_chars) ? int($nonfiling_chars) : 0; |
437 |
if ($nonfiling_chars) { |
438 |
$_data = substr $_data, $nonfiling_chars; |
439 |
} |
440 |
} |
414 |
push @{$record_document->{$target}}, $_data; |
441 |
push @{$record_document->{$target}}, $_data; |
415 |
} |
442 |
} |
416 |
} |
443 |
} |
Lines 448-460
sub marc_records_to_documents {
Link Here
|
448 |
my $record_document = {}; |
475 |
my $record_document = {}; |
449 |
my $mappings = $rules->{leader}; |
476 |
my $mappings = $rules->{leader}; |
450 |
if ($mappings) { |
477 |
if ($mappings) { |
451 |
$self->_process_mappings($mappings, $record->leader(), $record_document, 0); |
478 |
$self->_process_mappings($mappings, $record->leader(), $record_document, { |
|
|
479 |
altscript => 0, |
480 |
data_source => 'leader' |
481 |
} |
482 |
); |
452 |
} |
483 |
} |
453 |
foreach my $field ($record->fields()) { |
484 |
foreach my $field ($record->fields()) { |
454 |
if ($field->is_control_field()) { |
485 |
if ($field->is_control_field()) { |
455 |
my $mappings = $control_fields_rules->{$field->tag()}; |
486 |
my $mappings = $control_fields_rules->{$field->tag()}; |
456 |
if ($mappings) { |
487 |
if ($mappings) { |
457 |
$self->_process_mappings($mappings, $field->data(), $record_document, 0); |
488 |
$self->_process_mappings($mappings, $field->data(), $record_document, { |
|
|
489 |
altscript => 0, |
490 |
data_source => 'control_field', |
491 |
field => $field |
492 |
} |
493 |
); |
458 |
} |
494 |
} |
459 |
} |
495 |
} |
460 |
else { |
496 |
else { |
Lines 481-487
sub marc_records_to_documents {
Link Here
|
481 |
$mappings = [@{$mappings}, @{$wildcard_mappings}]; |
517 |
$mappings = [@{$mappings}, @{$wildcard_mappings}]; |
482 |
} |
518 |
} |
483 |
if (@{$mappings}) { |
519 |
if (@{$mappings}) { |
484 |
$self->_process_mappings($mappings, $data, $record_document, $altscript); |
520 |
$self->_process_mappings($mappings, $data, $record_document, { |
|
|
521 |
altscript => $altscript, |
522 |
data_source => 'subfield', |
523 |
code => $code, |
524 |
field => $field |
525 |
} |
526 |
); |
485 |
} |
527 |
} |
486 |
} |
528 |
} |
487 |
|
529 |
|
Lines 497-503
sub marc_records_to_documents {
Link Here
|
497 |
) |
539 |
) |
498 |
); |
540 |
); |
499 |
if ($data) { |
541 |
if ($data) { |
500 |
$self->_process_mappings($subfields_join_mappings->{$subfields_group}, $data, $record_document, $altscript); |
542 |
$self->_process_mappings($subfields_join_mappings->{$subfields_group}, $data, $record_document, { |
|
|
543 |
altscript => $altscript, |
544 |
data_source => 'subfields_group', |
545 |
codes => $subfields_group, |
546 |
field => $field |
547 |
} |
548 |
); |
501 |
} |
549 |
} |
502 |
} |
550 |
} |
503 |
} |
551 |
} |
Lines 786-792
sub _field_mappings {
Link Here
|
786 |
push @{$mapping}, {%{$default_options}, property => 'input'}; |
834 |
push @{$mapping}, {%{$default_options}, property => 'input'}; |
787 |
} |
835 |
} |
788 |
else { |
836 |
else { |
789 |
push @{$mapping}, $default_options; |
837 |
# Important! Make shallow clone, or we end up with the same hashref |
|
|
838 |
# shared by all mappings |
839 |
push @{$mapping}, {%{$default_options}}; |
790 |
} |
840 |
} |
791 |
push @mappings, $mapping; |
841 |
push @mappings, $mapping; |
792 |
} |
842 |
} |
Lines 905-911
sub _get_marc_mapping_rules {
Link Here
|
905 |
push @{$rules->{data_fields}->{$field_tag}->{subfields}->{$subfield}}, @mappings; |
955 |
push @{$rules->{data_fields}->{$field_tag}->{subfields}->{$subfield}}, @mappings; |
906 |
} |
956 |
} |
907 |
foreach my $subfield_group (@subfield_groups) { |
957 |
foreach my $subfield_group (@subfield_groups) { |
908 |
$rules->{data_fields}->{$field_tag}->{subfields_join}->{$subfield_group} //= []; |
958 |
$rules->{data_fields}->{$field_tag}->{subfields_join}->{$subfield_group} //= []; |
909 |
push @{$rules->{data_fields}->{$field_tag}->{subfields_join}->{$subfield_group}}, @mappings; |
959 |
push @{$rules->{data_fields}->{$field_tag}->{subfields_join}->{$subfield_group}}, @mappings; |
910 |
} |
960 |
} |
911 |
} |
961 |
} |
Lines 921-926
sub _get_marc_mapping_rules {
Link Here
|
921 |
); |
971 |
); |
922 |
} |
972 |
} |
923 |
}); |
973 |
}); |
|
|
974 |
|
975 |
# Marc-flavour specific rule tweaks, could/should also provide hook for this |
976 |
if ($marcflavour eq 'marc21') { |
977 |
# Nonfiling characters processing for sort fields |
978 |
my %title_fields; |
979 |
if ($self->index eq $Koha::SearchEngine::BIBLIOS_INDEX) { |
980 |
# Format is: nonfiling characters indicator => field names list |
981 |
%title_fields = ( |
982 |
1 => [630, 730, 740], |
983 |
2 => [130, 222, 240, 242, 243, 440, 830] |
984 |
); |
985 |
} |
986 |
elsif ($self->index eq $Koha::SearchEngine::AUTHORITIES_INDEX) { |
987 |
%title_fields = ( |
988 |
1 => [730], |
989 |
2 => [130, 430, 530] |
990 |
); |
991 |
} |
992 |
foreach my $indicator (keys %title_fields) { |
993 |
foreach my $field_tag (@{$title_fields{$indicator}}) { |
994 |
my $mappings = $rules->{data_fields}->{$field_tag}->{subfields}->{a} // []; |
995 |
foreach my $mapping (@{$mappings}) { |
996 |
if ($mapping->[0] =~ /__sort$/) { |
997 |
# Mark this as to be processed for nonfiling characters indicator |
998 |
# later on in _process_mappings |
999 |
$mapping->[1]->{nonfiling_characters_indicator} = $indicator; |
1000 |
} |
1001 |
} |
1002 |
} |
1003 |
} |
1004 |
} |
1005 |
|
924 |
return $rules; |
1006 |
return $rules; |
925 |
} |
1007 |
} |
926 |
|
1008 |
|