View | Details | Raw Unified | Return to bug 7284
Collapse All | Expand All

(-)a/C4/AuthoritiesMarc.pm (-102 / +83 lines)
Lines 17-25 package C4::AuthoritiesMarc; Link Here
17
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
18
19
use strict;
19
use strict;
20
#use warnings; FIXME - Bug 2505
20
use warnings;
21
use C4::Context;
21
use C4::Context;
22
use C4::Koha;
23
use MARC::Record;
22
use MARC::Record;
24
use C4::Biblio;
23
use C4::Biblio;
25
use C4::Search;
24
use C4::Search;
Lines 41-47 BEGIN { Link Here
41
	    &GetAuthType
40
	    &GetAuthType
42
	    &GetAuthTypeCode
41
	    &GetAuthTypeCode
43
    	&GetAuthMARCFromKohaField 
42
    	&GetAuthMARCFromKohaField 
44
    	&AUTHhtml2marc
45
43
46
    	&AddAuthority
44
    	&AddAuthority
47
    	&ModAuthority
45
    	&ModAuthority
Lines 98-112 sub GetAuthMARCFromKohaField { Link Here
98
=head2 SearchAuthorities 
96
=head2 SearchAuthorities 
99
97
100
  (\@finalresult, $nbresults)= &SearchAuthorities($tags, $and_or, 
98
  (\@finalresult, $nbresults)= &SearchAuthorities($tags, $and_or, 
101
     $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby)
99
     $excluding, $operator, $value, $offset,$length,$authtypecode,
100
     $sortby[, $skipmetadata])
102
101
103
returns ref to array result and count of results returned
102
returns ref to array result and count of results returned
104
103
105
=cut
104
=cut
106
105
107
sub SearchAuthorities {
106
sub SearchAuthorities {
108
    my ($tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby) = @_;
107
    my ($tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby,$skipmetadata) = @_;
109
#     warn "CALL : $tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby";
108
    # warn Dumper($tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby);
110
    my $dbh=C4::Context->dbh;
109
    my $dbh=C4::Context->dbh;
111
    if (C4::Context->preference('NoZebra')) {
110
    if (C4::Context->preference('NoZebra')) {
112
    
111
    
Lines 225-247 sub SearchAuthorities { Link Here
225
        for(my $i = 0 ; $i <= $#{$value} ; $i++)
224
        for(my $i = 0 ; $i <= $#{$value} ; $i++)
226
        {
225
        {
227
            if (@$value[$i]){
226
            if (@$value[$i]){
228
                if (@$tags[$i] eq "mainmainentry") {
227
                if ( @$tags[$i] eq "mainmainentry" ) {
229
228
                    $attr = " \@attr 1=Heading-Main ";
230
                $attr =" \@attr 1=Heading-Main ";
231
232
                }elsif (@$tags[$i] eq "mainentry") {
233
                $attr =" \@attr 1=Heading ";
234
                }else{
235
                $attr =" \@attr 1=Any ";
236
                }
229
                }
237
                if (@$operator[$i] eq 'is') {
230
                elsif ( @$tags[$i] eq "mainentry" ) {
238
                    $attr.=" \@attr 4=1  \@attr 5=100 ";##Phrase, No truncation,all of subfield field must match
231
                    $attr = " \@attr 1=Heading ";
239
                }elsif (@$operator[$i] eq "="){
232
                }
240
                    $attr.=" \@attr 4=107 ";           #Number Exact match
233
                elsif ( @$tags[$i] eq "any" ) {
241
                }elsif (@$operator[$i] eq "start"){
234
                    $attr = " \@attr 1=Any ";
242
                    $attr.=" \@attr 3=2 \@attr 4=1 \@attr 5=1 ";#Firstinfield Phrase, Right truncated
235
                }
243
                } else {
236
                elsif ( @$tags[$i] eq "match" ) {
244
                    $attr .=" \@attr 5=1 \@attr 4=6 ";## Word list, right truncated, anywhere
237
                    $attr = " \@attr 1=Match ";
238
                }
239
                elsif ( @$tags[$i] eq "match-heading" ) {
240
                    $attr = " \@attr 1=Match-heading ";
241
                }
242
                elsif ( @$tags[$i] eq "see-from" ) {
243
                    $attr = " \@attr 1=Match-heading-see-from ";
244
                }
245
                elsif ( @$tags[$i] eq "thesaurus" ) {
246
                    $attr = " \@attr 1=Subject-heading-thesaurus ";
247
                }
248
                if ( @$operator[$i] eq 'is' ) {
249
                    $attr .= " \@attr 4=1  \@attr 5=100 "
250
                      ; ##Phrase, No truncation,all of subfield field must match
251
                }
252
                elsif ( @$operator[$i] eq "=" ) {
253
                    $attr .= " \@attr 4=107 ";    #Number Exact match
254
                }
255
                elsif ( @$operator[$i] eq "start" ) {
256
                    $attr .= " \@attr 3=2 \@attr 4=1 \@attr 5=1 "
257
                      ;    #Firstinfield Phrase, Right truncated
258
                }
259
                elsif ( @$operator[$i] eq "exact" ) {
260
                    $attr .= " \@attr 4=1  \@attr 5=100 \@attr 6=3 "
261
                      ; ##Phrase, No truncation,all of subfield field must match
262
                }
263
                else {
264
                    $attr .= " \@attr 5=1 \@attr 4=6 "
265
                      ;    ## Word list, right truncated, anywhere
245
                }
266
                }
246
                @$value[$i] =~ s/"/\\"/g; # Escape the double-quotes in the search value
267
                @$value[$i] =~ s/"/\\"/g; # Escape the double-quotes in the search value
247
                $attr =$attr."\"".@$value[$i]."\"";
268
                $attr =$attr."\"".@$value[$i]."\"";
Lines 251-258 sub SearchAuthorities { Link Here
251
            }#if value
272
            }#if value
252
        }
273
        }
253
        ##Add how many queries generated
274
        ##Add how many queries generated
254
        if ($query=~/\S+/){
275
        if (defined $query && $query=~/\S+/){
255
          $query= $and x $attr_cnt . $query . $q2;
276
          $query= $and x $attr_cnt . $query . (defined $q2 ? $q2 : '');
256
        } else {
277
        } else {
257
          $query= $q2;
278
          $query= $q2;
258
        }
279
        }
Lines 309-343 sub SearchAuthorities { Link Here
309
            my $separator=C4::Context->preference('authoritysep');
330
            my $separator=C4::Context->preference('authoritysep');
310
            $authrecord = MARC::File::USMARC::decode($marcdata);
331
            $authrecord = MARC::File::USMARC::decode($marcdata);
311
            my $authid=$authrecord->field('001')->data(); 
332
            my $authid=$authrecord->field('001')->data(); 
312
            my $summary=BuildSummary($authrecord,$authid,$authtypecode);
313
            my $query_auth_tag = "SELECT auth_tag_to_report FROM auth_types WHERE authtypecode=?";
314
            my $sth = $dbh->prepare($query_auth_tag);
315
            $sth->execute($authtypecode);
316
            my $auth_tag_to_report = $sth->fetchrow;
317
            my $reported_tag;
318
            my $mainentry = $authrecord->field($auth_tag_to_report);
319
            if ($mainentry) {
320
                foreach ($mainentry->subfields()) {
321
                    $reported_tag .='$'.$_->[0].$_->[1];
322
                }
323
            }
324
            my %newline;
333
            my %newline;
325
            $newline{summary} = $summary;
326
            $newline{authid} = $authid;
334
            $newline{authid} = $authid;
327
            $newline{even} = $counter % 2;
335
            if ( !$skipmetadata ) {
328
            $newline{reported_tag} = $reported_tag;
336
                my $summary =
337
                  BuildSummary( $authrecord, $authid, $authtypecode );
338
                my $query_auth_tag =
339
"SELECT auth_tag_to_report FROM auth_types WHERE authtypecode=?";
340
                my $sth = $dbh->prepare($query_auth_tag);
341
                $sth->execute($authtypecode);
342
                my $auth_tag_to_report = $sth->fetchrow;
343
                my $reported_tag;
344
                my $mainentry = $authrecord->field($auth_tag_to_report);
345
                if ($mainentry) {
346
347
                    foreach ( $mainentry->subfields() ) {
348
                        $reported_tag .= '$' . $_->[0] . $_->[1];
349
                    }
350
                }
351
                $newline{summary}      = $summary;
352
                $newline{even}         = $counter % 2;
353
                $newline{reported_tag} = $reported_tag;
354
            }
329
            $counter++;
355
            $counter++;
330
            push @finalresult, \%newline;
356
            push @finalresult, \%newline;
331
            }## while counter
357
            }## while counter
332
        ###
358
            ###
333
        for (my $z=0; $z<@finalresult; $z++){
359
            if (! $skipmetadata) {
334
                my  $count=CountUsage($finalresult[$z]{authid});
360
                for (my $z=0; $z<@finalresult; $z++){
335
                $finalresult[$z]{used}=$count;
361
                    my  $count=CountUsage($finalresult[$z]{authid});
336
        }# all $z's
362
                    $finalresult[$z]{used}=$count;
337
        
363
                }# all $z's
364
            }
365
338
        }## if nbresult
366
        }## if nbresult
339
        NOLUCK:
367
        NOLUCK:
340
        # $oAResult->destroy();
368
        $oAResult->destroy();
341
        # $oAuth[0]->destroy();
369
        # $oAuth[0]->destroy();
342
        
370
        
343
        return (\@finalresult, $nbresults);
371
        return (\@finalresult, $nbresults);
Lines 854-906 sub GetAuthType { Link Here
854
}
882
}
855
883
856
884
857
sub AUTHhtml2marc {
858
    my ($rtags,$rsubfields,$rvalues,%indicators) = @_;
859
    my $dbh=C4::Context->dbh;
860
    my $prevtag = -1;
861
    my $record = MARC::Record->new();
862
#---- TODO : the leader is missing
863
864
#     my %subfieldlist=();
865
    my $prevvalue; # if tag <10
866
    my $field; # if tag >=10
867
    for (my $i=0; $i< @$rtags; $i++) {
868
        # rebuild MARC::Record
869
        if (@$rtags[$i] ne $prevtag) {
870
            if ($prevtag < 10) {
871
                if ($prevvalue) {
872
                    $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
873
                }
874
            } else {
875
                if ($field) {
876
                    $record->add_fields($field);
877
                }
878
            }
879
            $indicators{@$rtags[$i]}.='  ';
880
            if (@$rtags[$i] <10) {
881
                $prevvalue= @$rvalues[$i];
882
                undef $field;
883
            } else {
884
                undef $prevvalue;
885
                $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
886
            }
887
            $prevtag = @$rtags[$i];
888
        } else {
889
            if (@$rtags[$i] <10) {
890
                $prevvalue=@$rvalues[$i];
891
            } else {
892
                if (length(@$rvalues[$i])>0) {
893
                    $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
894
                }
895
            }
896
            $prevtag= @$rtags[$i];
897
        }
898
    }
899
    # the last has not been included inside the loop... do it now !
900
    $record->add_fields($field) if $field;
901
    return $record;
902
}
903
904
=head2 FindDuplicateAuthority
885
=head2 FindDuplicateAuthority
905
886
906
  $record= &FindDuplicateAuthority( $record, $authtypecode)
887
  $record= &FindDuplicateAuthority( $record, $authtypecode)
Lines 1015-1028 sub BuildSummary{ Link Here
1015
    $resultstring =~ s/\n/<br>/g;
996
    $resultstring =~ s/\n/<br>/g;
1016
	$summary      =  $resultstring;
997
	$summary      =  $resultstring;
1017
  } else {
998
  } else {
1018
    my $heading; 
999
    my $heading = '';
1019
    my $altheading;
1000
    my $altheading = '';
1020
    my $seealso;
1001
    my $seealso = '';
1021
    my $broaderterms;
1002
    my $broaderterms = '';
1022
    my $narrowerterms;
1003
    my $narrowerterms = '';
1023
    my $see;
1004
    my $see = '';
1024
    my $seeheading;
1005
    my $seeheading = '';
1025
        my $notes;
1006
    my $notes = '';
1026
    my @fields = $record->fields();
1007
    my @fields = $record->fields();
1027
    if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
1008
    if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
1028
    # construct UNIMARC summary, that is quite different from MARC21 one
1009
    # construct UNIMARC summary, that is quite different from MARC21 one
Lines 1471-1477 sub get_auth_type_location { Link Here
1471
    my $auth_type_code = @_ ? shift : '';
1452
    my $auth_type_code = @_ ? shift : '';
1472
1453
1473
    my ($tag, $subfield) = GetAuthMARCFromKohaField('auth_header.authtypecode', $auth_type_code);
1454
    my ($tag, $subfield) = GetAuthMARCFromKohaField('auth_header.authtypecode', $auth_type_code);
1474
    if (defined $tag and defined $subfield and $tag != 0 and $subfield != 0) {
1455
    if (defined $tag and defined $subfield and $tag != 0 and $subfield ne '' and $subfield ne ' ') {
1475
        return ($tag, $subfield);
1456
        return ($tag, $subfield);
1476
    } else {
1457
    } else {
1477
        if (C4::Context->preference('marcflavour') eq "MARC21")  {
1458
        if (C4::Context->preference('marcflavour') eq "MARC21")  {
(-)a/C4/Biblio.pm (-16 / +126 lines)
Lines 34-39 use C4::Dates qw/format_date/; Link Here
34
use C4::Log;    # logaction
34
use C4::Log;    # logaction
35
use C4::ClassSource;
35
use C4::ClassSource;
36
use C4::Charset;
36
use C4::Charset;
37
use C4::Linker;
37
38
38
use vars qw($VERSION @ISA @EXPORT);
39
use vars qw($VERSION @ISA @EXPORT);
39
40
Lines 110-115 BEGIN { Link Here
110
    # To link headings in a bib record
111
    # To link headings in a bib record
111
    # to authority records.
112
    # to authority records.
112
    push @EXPORT, qw(
113
    push @EXPORT, qw(
114
      &BiblioAutoLink
113
      &LinkBibHeadingsToAuthorities
115
      &LinkBibHeadingsToAuthorities
114
    );
116
    );
115
117
Lines 449-457 sub DelBiblio { Link Here
449
    return;
451
    return;
450
}
452
}
451
453
454
455
=head2 BiblioAutoLink
456
457
  my $headings_linked = BiblioAutoLink($record, $frameworkcode)
458
459
Automatically links headings in a bib record to authorities.
460
461
=cut
462
463
sub BiblioAutoLink {
464
    my $record        = shift;
465
    my $frameworkcode = shift;
466
    my ( $num_headings_changed, %results );
467
468
    my $linker_module =
469
      "C4::Linker::" . ( C4::Context->preference("LinkerModule") || 'Default' );
470
    eval { eval "require $linker_module"; };
471
    if ($@) {
472
        $linker_module = 'C4::Linker::Default';
473
        eval "require $linker_module";
474
    }
475
    if ($@) {
476
        return 0, 0;
477
    }
478
479
    my $linker = $linker_module->new(
480
        { 'options' => C4::Context->preference("LinkerOptions") } );
481
    my ( $headings_changed, undef ) =
482
      LinkBibHeadingsToAuthorities( $linker, $record, $frameworkcode, C4::Context->preference("CatalogModuleRelink") || '' );
483
    # By default we probably don't want to relink things when cataloging
484
    return $headings_changed;
485
}
486
452
=head2 LinkBibHeadingsToAuthorities
487
=head2 LinkBibHeadingsToAuthorities
453
488
454
  my $headings_linked = LinkBibHeadingsToAuthorities($marc);
489
  my $num_headings_changed, %results = LinkBibHeadingsToAuthorities($linker, $marc, $frameworkcode, [$allowrelink]);
455
490
456
Links bib headings to authority records by checking
491
Links bib headings to authority records by checking
457
each authority-controlled field in the C<MARC::Record>
492
each authority-controlled field in the C<MARC::Record>
Lines 459-467 object C<$marc>, looking for a matching authority record, Link Here
459
and setting the linking subfield $9 to the ID of that
494
and setting the linking subfield $9 to the ID of that
460
authority record.  
495
authority record.  
461
496
462
If no matching authority exists, or if multiple
497
If $allowrelink is false, existing authids will never be
463
authorities match, no $9 will be added, and any 
498
replaced, regardless of the values of LinkerKeepStale and
464
existing one inthe field will be deleted.
499
LinkerRelink.
465
500
466
Returns the number of heading links changed in the
501
Returns the number of heading links changed in the
467
MARC record.
502
MARC record.
Lines 469-506 MARC record. Link Here
469
=cut
504
=cut
470
505
471
sub LinkBibHeadingsToAuthorities {
506
sub LinkBibHeadingsToAuthorities {
507
    my $linker        = shift;
508
    my $bib           = shift;
509
    my $frameworkcode = shift;
510
    my $allowrelink = shift;
511
    my %results;
472
    require C4::Heading;
512
    require C4::Heading;
473
    my $bib = shift;
513
    require C4::AuthoritiesMarc;
474
514
515
    $allowrelink = 1 unless defined $allowrelink;
475
    my $num_headings_changed = 0;
516
    my $num_headings_changed = 0;
476
    foreach my $field ( $bib->fields() ) {
517
    foreach my $field ( $bib->fields() ) {
477
        my $heading = C4::Heading->new_from_bib_field($field);
518
        my $heading = C4::Heading->new_from_bib_field( $field, $frameworkcode );
478
        next unless defined $heading;
519
        next unless defined $heading;
479
520
480
        # check existing $9
521
        # check existing $9
481
        my $current_link = $field->subfield('9');
522
        my $current_link = $field->subfield('9');
482
523
483
        # look for matching authorities
524
        if ( defined $current_link && (!$allowrelink || !C4::Context->preference('LinkerRelink')) )
484
        my $authorities = $heading->authorities();
525
        {
526
            $results{'linked'}->{ $heading->display_form() }++;
527
            next;
528
        }
485
529
486
        # want only one exact match
530
        my ( $authid, $fuzzy ) = $linker->get_link($heading);
487
        if ( $#{$authorities} == 0 ) {
531
        if ($authid) {
488
            my $authority = MARC::Record->new_from_usmarc( $authorities->[0] );
532
            $results{ $fuzzy ? 'fuzzy' : 'linked' }
489
            my $authid    = $authority->field('001')->data();
533
              ->{ $heading->display_form() }++;
490
            next if defined $current_link and $current_link eq $authid;
534
            next if defined $current_link and $current_link == $authid;
491
535
492
            $field->delete_subfield( code => '9' ) if defined $current_link;
536
            $field->delete_subfield( code => '9' ) if defined $current_link;
493
            $field->add_subfields( '9', $authid );
537
            $field->add_subfields( '9', $authid );
494
            $num_headings_changed++;
538
            $num_headings_changed++;
495
        } else {
539
        }
496
            if ( defined $current_link ) {
540
        else {
541
            if ( defined $current_link
542
                && (!$allowrelink || C4::Context->preference('LinkerKeepStale')) )
543
            {
544
                $results{'fuzzy'}->{ $heading->display_form() }++;
545
            }
546
            elsif ( C4::Context->preference('AutoCreateAuthorities') ) {
547
                my $authtypedata =
548
                  C4::AuthoritiesMarc::GetAuthType( $heading->auth_type() );
549
                my $marcrecordauth = MARC::Record->new();
550
                if ( C4::Context->preference('marcflavour') eq 'MARC21' ) {
551
                    $marcrecordauth->leader('     nz  a22     o  4500');
552
                    SetMarcUnicodeFlag( $marcrecordauth, 'MARC21' );
553
                }
554
                my $authfield =
555
                  MARC::Field->new( $authtypedata->{auth_tag_to_report},
556
                    '', '', "a" => "" . $field->subfield('a') );
557
                map {
558
                    $authfield->add_subfields( $_->[0] => $_->[1] )
559
                      if ( $_->[0] =~ /[A-z]/ && $_->[0] ne "a" )
560
                } $field->subfields();
561
                $marcrecordauth->insert_fields_ordered($authfield);
562
563
# bug 2317: ensure new authority knows it's using UTF-8; currently
564
# only need to do this for MARC21, as MARC::Record->as_xml_record() handles
565
# automatically for UNIMARC (by not transcoding)
566
# FIXME: AddAuthority() instead should simply explicitly require that the MARC::Record
567
# use UTF-8, but as of 2008-08-05, did not want to introduce that kind
568
# of change to a core API just before the 3.0 release.
569
570
                if ( C4::Context->preference('marcflavour') eq 'MARC21' ) {
571
                    $marcrecordauth->insert_fields_ordered(
572
                        MARC::Field->new(
573
                            '667', '', '',
574
                            'a' => "Machine generated authority record."
575
                        )
576
                    );
577
                    my $cite =
578
                        $bib->author() . ", "
579
                      . $bib->title_proper() . ", "
580
                      . $bib->publication_date() . " ";
581
                    $cite =~ s/^[\s\,]*//;
582
                    $cite =~ s/[\s\,]*$//;
583
                    $cite =
584
                        "Work cat.: ("
585
                      . C4::Context->preference('MARCOrgCode') . ")"
586
                      . $bib->subfield( '999', 'c' ) . ": "
587
                      . $cite;
588
                    $marcrecordauth->insert_fields_ordered(
589
                        MARC::Field->new( '670', '', '', 'a' => $cite ) );
590
                }
591
592
           #          warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
593
594
                $authid =
595
                  C4::AuthoritiesMarc::AddAuthority( $marcrecordauth, '',
596
                    $heading->auth_type() );
597
                $field->add_subfields( '9', $authid );
598
                $num_headings_changed++;
599
                $results{'added'}->{ $heading->display_form() }++;
600
            }
601
            elsif ( defined $current_link ) {
497
                $field->delete_subfield( code => '9' );
602
                $field->delete_subfield( code => '9' );
498
                $num_headings_changed++;
603
                $num_headings_changed++;
604
                $results{'unlinked'}->{ $heading->display_form() }++;
605
            }
606
            else {
607
                $results{'unlinked'}->{ $heading->display_form() }++;
499
            }
608
            }
500
        }
609
        }
501
610
502
    }
611
    }
503
    return $num_headings_changed;
612
    return $num_headings_changed, \%results;
504
}
613
}
505
614
506
=head2 GetRecordValue
615
=head2 GetRecordValue
Lines 1864-1869 sub PrepHostMarcField { Link Here
1864
    my ($hostbiblionumber,$hostitemnumber, $marcflavour) = @_;
1973
    my ($hostbiblionumber,$hostitemnumber, $marcflavour) = @_;
1865
    $marcflavour ||="MARC21";
1974
    $marcflavour ||="MARC21";
1866
    
1975
    
1976
    require C4::Items;
1867
    my $hostrecord = GetMarcBiblio($hostbiblionumber);
1977
    my $hostrecord = GetMarcBiblio($hostbiblionumber);
1868
	my $item = C4::Items::GetItem($hostitemnumber);
1978
	my $item = C4::Items::GetItem($hostitemnumber);
1869
	
1979
	
(-)a/C4/Heading.pm (-55 / +101 lines)
Lines 1-7 Link Here
1
package C4::Heading;
1
package C4::Heading;
2
2
3
# Copyright (C) 2008 LibLime
3
# Copyright (C) 2008 LibLime
4
# 
4
#
5
# This file is part of Koha.
5
# This file is part of Koha.
6
#
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
7
# Koha is free software; you can redistribute it and/or modify it under the
Lines 18-28 package C4::Heading; Link Here
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
19
20
use strict;
20
use strict;
21
#use warnings; FIXME - Bug 2505
21
use warnings;
22
use MARC::Record;
22
use MARC::Record;
23
use MARC::Field;
23
use MARC::Field;
24
use C4::Context;
24
use C4::Context;
25
use C4::Heading::MARC21;
25
use Module::Load;
26
use Carp;
26
use Carp;
27
27
28
our $VERSION = 3.00;
28
our $VERSION = 3.00;
Lines 34-44 C4::Heading Link Here
34
=head1 SYNOPSIS
34
=head1 SYNOPSIS
35
35
36
 use C4::Heading;
36
 use C4::Heading;
37
 my $heading = C4::Heading->new_from_bib_field($field);
37
 my $heading = C4::Heading->new_from_bib_field($field, $frameworkcode);
38
 my $thesaurus = $heading->thesaurus();
38
 my $thesaurus = $heading->thesaurus();
39
 my $type = $heading->type();
39
 my $type = $heading->type();
40
 my $display_heading = $heading->display();
40
 my $display_heading = $heading->display_form();
41
 my $search_string = $heading->search_string();
41
 my $search_form = $heading->search_form();
42
42
43
=head1 DESCRIPTION
43
=head1 DESCRIPTION
44
44
Lines 49-55 headings found in bibliographic and authority records. Link Here
49
49
50
=head2 new_from_bib_field
50
=head2 new_from_bib_field
51
51
52
  my $heading = C4::Heading->new_from_bib_field($field[, $marc_flavour]);
52
  my $heading = C4::Heading->new_from_bib_field($field, $frameworkcode, [, $marc_flavour]);
53
53
54
Given a C<MARC::Field> object containing a heading from a 
54
Given a C<MARC::Field> object containing a heading from a 
55
bib record, create a C<C4::Heading> object.
55
bib record, create a C<C4::Heading> object.
Lines 64-87 is returned. Link Here
64
=cut
64
=cut
65
65
66
sub new_from_bib_field {
66
sub new_from_bib_field {
67
    my $class = shift;
67
    my $class         = shift;
68
    my $field = shift;
68
    my $field         = shift;
69
    my $marcflavour = @_ ? shift : C4::Context->preference('marcflavour');
69
    my $frameworkcode = shift;
70
    my $marcflavour   = @_ ? shift : C4::Context->preference('marcflavour');
70
71
71
    my $marc_handler = _marc_format_handler($marcflavour);
72
    my $marc_handler = _marc_format_handler($marcflavour);
72
73
73
    my $tag = $field->tag();
74
    my $tag = $field->tag();
74
    return unless $marc_handler->valid_bib_heading_tag($tag);
75
    return unless $marc_handler->valid_bib_heading_tag( $tag, $frameworkcode );
75
    my $self = {};
76
    my $self = {};
76
   
77
77
    ($self->{'auth_type'}, $self->{'subject_added_entry'}, $self->{'series_added_entry'}, $self->{'main_entry'},
78
    $self->{'field'} = $field;
78
     $self->{'thesaurus'}, $self->{'search_form'}, $self->{'display_form'}) =
79
    (
79
        $marc_handler->parse_heading($field);
80
        $self->{'auth_type'},   $self->{'thesaurus'},
81
        $self->{'search_form'}, $self->{'display_form'},
82
        $self->{'match_type'}
83
    ) = $marc_handler->parse_heading($field);
80
84
81
    bless $self, $class;
85
    bless $self, $class;
82
    return $self;
86
    return $self;
83
}
87
}
84
88
89
=head2 auth_type
90
91
  my $auth_type = $heading->auth_type();
92
93
Return the auth_type of the heading.
94
95
=cut
96
97
sub auth_type {
98
    my $self = shift;
99
    return $self->{'auth_type'};
100
}
101
102
=head2 field
103
104
  my $field = $heading->field();
105
106
Return the MARC::Field the heading is based on.
107
108
=cut
109
110
sub field {
111
    my $self = shift;
112
    return $self->{'field'};
113
}
114
85
=head2 display_form
115
=head2 display_form
86
116
87
  my $display = $heading->display_form();
117
  my $display = $heading->display_form();
Lines 95-118 sub display_form { Link Here
95
    return $self->{'display_form'};
125
    return $self->{'display_form'};
96
}
126
}
97
127
128
=head2 search_form
129
130
  my $search_form = $heading->search_form();
131
132
Return the "canonical" search form of the heading.
133
134
=cut
135
136
sub search_form {
137
    my $self = shift;
138
    return $self->{'search_form'};
139
}
140
98
=head2 authorities
141
=head2 authorities
99
142
100
  my $authorities = $heading->authorities;
143
  my $authorities = $heading->authorities([$skipmetadata]);
101
144
102
Return a list of authority records for this 
145
Return a list of authority records for this 
103
heading.
146
heading. If passed a true value for $skipmetadata,
147
SearchAuthorities will return only authids.
104
148
105
=cut
149
=cut
106
150
107
sub authorities {
151
sub authorities {
108
    my $self = shift;
152
    my $self         = shift;
109
    my $query = qq(Match-heading,do-not-truncate,ext="$self->{'search_form'}");
153
    my $skipmetadata = shift;
110
    $query .= $self->_query_limiters();
154
    my ( $results, $total ) = _search( $self, 'match-heading', $skipmetadata );
111
    require C4::Search;
112
    my ($error, $results, $total_hits) = C4::Search::SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
113
    if (defined $error) {
114
        carp "Error:$error from search $query";
115
    }
116
    return $results;
155
    return $results;
117
}
156
}
118
157
Lines 127-163 that are a preferred form of the heading. Link Here
127
166
128
sub preferred_authorities {
167
sub preferred_authorities {
129
    my $self = shift;
168
    my $self = shift;
130
    my $query = "Match-heading-see-from,do-not-truncate,ext='$self->{'search_form'}'";
169
    my $skipmetadata = shift || undef;
131
    $query .= $self->_query_limiters();
170
    my ( $results, $total ) = _search( 'see-from', $skipmetadata );
132
    require C4::Search;
133
    my ($error, $results, $total_hits) = C4::Search::SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
134
    if (defined $error) {
135
        carp "Error:$error from search $query";
136
    }
137
    return $results;
171
    return $results;
138
}
172
}
139
173
140
=head1 INTERNAL METHODS
174
=head1 INTERNAL METHODS
141
175
142
=head2 _query_limiters
176
=head2 _search
143
177
144
=cut
178
=cut
145
179
146
sub _query_limiters {
180
sub _search {
147
    my $self = shift;
181
    my $self         = shift;
148
182
    my $index        = shift || undef;
149
    my $limiters = " AND at='$self->{'auth_type'}'";
183
    my $skipmetadata = shift || undef;
150
    if ($self->{'subject_added_entry'}) {
184
    my @marclist;
151
        $limiters .= " AND Heading-use-subject-added-entry=a"; # FIXME -- is this properly in C4::Heading::MARC21?
185
    my @and_or;
152
        $limiters .= " AND Subject-heading-thesaurus=$self->{'thesaurus'}";
186
    my @excluding = [];
153
    }
187
    my @operator;
154
    if ($self->{'series_added_entry'}) {
188
    my @value;
155
        $limiters .= " AND Heading-use-series-added-entry=a"; # FIXME -- is this properly in C4::Heading::MARC21?
189
156
    }
190
    if ($index) {
157
    if (not $self->{'subject_added_entry'} and not $self->{'series_added_entry'}) {
191
        push @marclist, $index;
158
        $limiters .= " AND Heading-use-main-or-added-entry=a" # FIXME -- is this properly in C4::Heading::MARC21?
192
        push @and_or,   'and';
193
        push @operator, $self->{'match_type'};
194
        push @value,    $self->{'search_form'};
159
    }
195
    }
160
    return $limiters;
196
197
    #    if ($self->{'thesaurus'}) {
198
    #        push @marclist, 'thesaurus';
199
    #        push @and_or, 'and';
200
    #        push @excluding, '';
201
    #        push @operator, 'is';
202
    #        push @value, $self->{'thesaurus'};
203
    #    }
204
    require C4::AuthoritiesMarc;
205
    return C4::AuthoritiesMarc::SearchAuthorities(
206
        \@marclist, \@and_or, \@excluding, \@operator,
207
        \@value,    0,        20,          $self->{'auth_type'},
208
        '',         $skipmetadata
209
    );
161
}
210
}
162
211
163
=head1 INTERNAL FUNCTIONS
212
=head1 INTERNAL FUNCTIONS
Lines 170-183 depending on the selected MARC flavour. Link Here
170
=cut
219
=cut
171
220
172
sub _marc_format_handler {
221
sub _marc_format_handler {
173
    my $marcflavour = shift;
222
    my $marcflavour = uc shift;
174
223
    $marcflavour = 'MARC21' if ( $marcflavour eq 'NORMARC' );
175
    if ($marcflavour eq 'UNIMARC') {
224
    my $pname = "C4::Heading::$marcflavour";
176
        return C4::Heading::UNIMARC->new();
225
    load $pname;
177
    } else {
226
    return $pname->new();
178
        return C4::Heading::MARC21->new();
179
    }
180
181
}
227
}
182
228
183
=head1 AUTHOR
229
=head1 AUTHOR
(-)a/C4/Heading/MARC21.pm (-64 / +134 lines)
Lines 1-7 Link Here
1
package C4::Heading::MARC21;
1
package C4::Heading::MARC21;
2
2
3
# Copyright (C) 2008 LibLime
3
# Copyright (C) 2008 LibLime
4
# 
4
#
5
# This file is part of Koha.
5
# This file is part of Koha.
6
#
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
7
# Koha is free software; you can redistribute it and/or modify it under the
Lines 18-24 package C4::Heading::MARC21; Link Here
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
19
20
use strict;
20
use strict;
21
#use warnings; FIXME - Bug 2505
21
use warnings;
22
use MARC::Record;
22
use MARC::Record;
23
use MARC::Field;
23
use MARC::Field;
24
24
Lines 49-75 FIXME - this should be moved to a configuration file. Link Here
49
=cut
49
=cut
50
50
51
my $bib_heading_fields = {
51
my $bib_heading_fields = {
52
    '100' => { auth_type => 'PERSO_NAME', subfields => 'abcdefghjklmnopqrst', main_entry => 1 },
52
    '100' => {
53
    '110' => { auth_type => 'CORPO_NAME', subfields => 'abcdefghklmnoprst', main_entry => 1 },
53
        auth_type  => 'PERSO_NAME',
54
    '111' => { auth_type => 'MEETI_NAME', subfields => 'acdefghjklnpqst', main_entry => 1 },
54
        subfields  => 'abcdfghjklmnopqrst',
55
    '130' => { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprst', main_entry => 1 },
55
        main_entry => 1
56
    },
57
    '110' => {
58
        auth_type  => 'CORPO_NAME',
59
        subfields  => 'abcdfghklmnoprst',
60
        main_entry => 1
61
    },
62
    '111' => {
63
        auth_type  => 'MEETI_NAME',
64
        subfields  => 'acdfghjklnpqst',
65
        main_entry => 1
66
    },
67
    '130' => {
68
        auth_type  => 'UNIF_TITLE',
69
        subfields  => 'adfghklmnoprst',
70
        main_entry => 1
71
    },
56
    '440' => { auth_type => 'UNIF_TITLE', subfields => 'anp', series => 1 },
72
    '440' => { auth_type => 'UNIF_TITLE', subfields => 'anp', series => 1 },
57
    '600' => { auth_type => 'PERSO_NAME', subfields => 'abcdefghjklmnopqrstvxyz', subject => 1 },
73
    '600' => {
58
    '610' => { auth_type => 'CORPO_NAME', subfields => 'abcdefghklmnoprstvxyz', subject => 1 },
74
        auth_type => 'PERSO_NAME',
59
    '611' => { auth_type => 'MEETI_NAME', subfields => 'acdefghjklnpqstvxyz', subject => 1 },
75
        subfields => 'abcdfghjklmnopqrstvxyz',
60
    '630' => { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprstvxyz', subject => 1 },
76
        subject   => 1
61
    '648' => { auth_type => 'CHRON_TERM', subfields => 'avxyz', subject => 1 },
77
    },
78
    '610' => {
79
        auth_type => 'CORPO_NAME',
80
        subfields => 'abcdfghklmnoprstvxyz',
81
        subject   => 1
82
    },
83
    '611' => {
84
        auth_type => 'MEETI_NAME',
85
        subfields => 'acdfghjklnpqstvxyz',
86
        subject   => 1
87
    },
88
    '630' => {
89
        auth_type => 'UNIF_TITLE',
90
        subfields => 'adfghklmnoprstvxyz',
91
        subject   => 1
92
    },
93
    '648' => { auth_type => 'CHRON_TERM', subfields => 'avxyz',  subject => 1 },
62
    '650' => { auth_type => 'TOPIC_TERM', subfields => 'abvxyz', subject => 1 },
94
    '650' => { auth_type => 'TOPIC_TERM', subfields => 'abvxyz', subject => 1 },
63
    '651' => { auth_type => 'GEOGR_NAME', subfields => 'avxyz', subject => 1 },
95
    '651' => { auth_type => 'GEOGR_NAME', subfields => 'avxyz',  subject => 1 },
64
    '655' => { auth_type => 'GENRE/FORM', subfields => 'avxyz', subject => 1 },
96
    '655' => { auth_type => 'GENRE/FORM', subfields => 'avxyz',  subject => 1 },
65
    '700' => { auth_type => 'PERSO_NAME', subfields => 'abcdefghjklmnopqrst' },
97
    '700' => { auth_type => 'PERSO_NAME', subfields => 'abcdfghjklmnopqrst' },
66
    '710' => { auth_type => 'CORPO_NAME', subfields => 'abcdefghklmnoprst' },
98
    '710' => { auth_type => 'CORPO_NAME', subfields => 'abcdfghklmnoprst' },
67
    '711' => { auth_type => 'MEETI_NAME', subfields => 'acdefghjklnpqst' },
99
    '711' => { auth_type => 'MEETI_NAME', subfields => 'acdfghjklnpqst' },
68
    '730' => { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprst' },
100
    '730' => { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprst' },
69
    '800' => { auth_type => 'PERSO_NAME', subfields => 'abcdefghjklmnopqrst', series => 1 },
101
    '800' => {
70
    '810' => { auth_type => 'CORPO_NAME', subfields => 'abcdefghklmnoprst', series => 1 },
102
        auth_type => 'PERSO_NAME',
71
    '811' => { auth_type => 'MEETI_NAME', subfields => 'acdefghjklnpqst', series => 1 },
103
        subfields => 'abcdfghjklmnopqrst',
72
    '830' => { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprst', series => 1 },
104
        series    => 1
105
    },
106
    '810' => {
107
        auth_type => 'CORPO_NAME',
108
        subfields => 'abcdfghklmnoprst',
109
        series    => 1
110
    },
111
    '811' =>
112
      { auth_type => 'MEETI_NAME', subfields => 'acdfghjklnpqst', series => 1 },
113
    '830' =>
114
      { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprst', series => 1 },
73
};
115
};
74
116
75
=head2 subdivisions
117
=head2 subdivisions
Lines 101-112 sub new { Link Here
101
=cut
143
=cut
102
144
103
sub valid_bib_heading_tag {
145
sub valid_bib_heading_tag {
104
    my $self = shift;
146
    my $self          = shift;
105
    my $tag = shift;
147
    my $tag           = shift;
148
    my $frameworkcode = shift;
106
149
107
    if (exists $bib_heading_fields->{$tag}) {
150
    if ( exists $bib_heading_fields->{$tag} ) {
108
        return 1
151
        return 1;
109
    } else {
152
    }
153
    else {
110
        return 0;
154
        return 0;
111
    }
155
    }
112
156
Lines 117-137 sub valid_bib_heading_tag { Link Here
117
=cut
161
=cut
118
162
119
sub parse_heading {
163
sub parse_heading {
120
    my $self = shift;
164
    my $self  = shift;
121
    my $field = shift;
165
    my $field = shift;
122
166
123
    my $tag = $field->tag;
167
    my $tag        = $field->tag;
124
    my $field_info = $bib_heading_fields->{$tag};
168
    my $field_info = $bib_heading_fields->{$tag};
125
169
126
    my $auth_type = $field_info->{'auth_type'};
170
    my $auth_type = $field_info->{'auth_type'};
127
    my $subject = $field_info->{'subject'} ? 1 : 0;
171
    my $thesaurus =
128
    my $series = $field_info->{'series'} ? 1 : 0;
172
      $tag =~ m/6../
129
    my $main_entry = $field_info->{'main_entry'} ? 1 : 0;
173
      ? _get_subject_thesaurus($field)
130
    my $thesaurus = $subject ? _get_subject_thesaurus($field) : "lcsh"; # use 'lcsh' for names, UT, etc.
174
      : "lcsh";    # use 'lcsh' for names, UT, etc.
131
    my $search_heading = _get_search_heading($field, $field_info->{'subfields'});
175
    my $search_heading =
132
    my $display_heading = _get_display_heading($field, $field_info->{'subfields'});
176
      _get_search_heading( $field, $field_info->{'subfields'} );
133
177
    my $display_heading =
134
    return ($auth_type, $subject, $series, $main_entry, $thesaurus, $search_heading, $display_heading);
178
      _get_display_heading( $field, $field_info->{'subfields'} );
179
180
    return ( $auth_type, $thesaurus, $search_heading, $display_heading,
181
        'exact' );
135
}
182
}
136
183
137
=head1 INTERNAL FUNCTIONS
184
=head1 INTERNAL FUNCTIONS
Lines 142-165 sub parse_heading { Link Here
142
189
143
sub _get_subject_thesaurus {
190
sub _get_subject_thesaurus {
144
    my $field = shift;
191
    my $field = shift;
145
    my $ind2 = $field->indicator(2);
192
    my $ind2  = $field->indicator(2);
146
193
147
    my $thesaurus = "notdefined";
194
    my $thesaurus = "notdefined";
148
    if ($ind2 eq '0') {
195
    if ( $ind2 eq '0' ) {
149
        $thesaurus = "lcsh";
196
        $thesaurus = "lcsh";
150
    } elsif ($ind2 eq '1') {
197
    }
198
    elsif ( $ind2 eq '1' ) {
151
        $thesaurus = "lcac";
199
        $thesaurus = "lcac";
152
    } elsif ($ind2 eq '2') {
200
    }
201
    elsif ( $ind2 eq '2' ) {
153
        $thesaurus = "mesh";
202
        $thesaurus = "mesh";
154
    } elsif ($ind2 eq '3') {
203
    }
204
    elsif ( $ind2 eq '3' ) {
155
        $thesaurus = "nal";
205
        $thesaurus = "nal";
156
    } elsif ($ind2 eq '4') {
206
    }
207
    elsif ( $ind2 eq '4' ) {
157
        $thesaurus = "notspecified";
208
        $thesaurus = "notspecified";
158
    } elsif ($ind2 eq '5') {
209
    }
210
    elsif ( $ind2 eq '5' ) {
159
        $thesaurus = "cash";
211
        $thesaurus = "cash";
160
    } elsif ($ind2 eq '6') {
212
    }
213
    elsif ( $ind2 eq '6' ) {
161
        $thesaurus = "rvm";
214
        $thesaurus = "rvm";
162
    } elsif ($ind2 eq '7') {
215
    }
216
    elsif ( $ind2 eq '7' ) {
163
        my $sf2 = $field->subfield('2');
217
        my $sf2 = $field->subfield('2');
164
        $thesaurus = $sf2 if defined($sf2);
218
        $thesaurus = $sf2 if defined($sf2);
165
    }
219
    }
Lines 172-195 sub _get_subject_thesaurus { Link Here
172
=cut
226
=cut
173
227
174
sub _get_search_heading {
228
sub _get_search_heading {
175
    my $field = shift;
229
    my $field     = shift;
176
    my $subfields = shift;
230
    my $subfields = shift;
177
231
178
    my $heading = "";
232
    my $heading   = "";
179
    my @subfields = $field->subfields();
233
    my @subfields = $field->subfields();
180
    my $first = 1;
234
    my $first     = 1;
181
    for (my $i = 0; $i <= $#subfields; $i++) {
235
    for ( my $i = 0 ; $i <= $#subfields ; $i++ ) {
182
        my $code = $subfields[$i]->[0];
236
        my $code    = $subfields[$i]->[0];
183
        my $code_re = quotemeta $code;
237
        my $code_re = quotemeta $code;
184
        my $value = $subfields[$i]->[1];
238
        my $value   = $subfields[$i]->[1];
239
        $value =~ s/[-,.:=;!%\/]$//;
185
        next unless $subfields =~ qr/$code_re/;
240
        next unless $subfields =~ qr/$code_re/;
186
        if ($first) {
241
        if ($first) {
187
            $first = 0;
242
            $first   = 0;
188
            $heading = $value;
243
            $heading = $value;
189
        } else {
244
        }
190
            if (exists $subdivisions{$code}) {
245
        else {
246
            if ( exists $subdivisions{$code} ) {
191
                $heading .= " $subdivisions{$code} $value";
247
                $heading .= " $subdivisions{$code} $value";
192
            } else {
248
            }
249
            else {
193
                $heading .= " $value";
250
                $heading .= " $value";
194
            }
251
            }
195
        }
252
        }
Lines 206-229 sub _get_search_heading { Link Here
206
=cut
263
=cut
207
264
208
sub _get_display_heading {
265
sub _get_display_heading {
209
    my $field = shift;
266
    my $field     = shift;
210
    my $subfields = shift;
267
    my $subfields = shift;
211
268
212
    my $heading = "";
269
    my $heading   = "";
213
    my @subfields = $field->subfields();
270
    my @subfields = $field->subfields();
214
    my $first = 1;
271
    my $first     = 1;
215
    for (my $i = 0; $i <= $#subfields; $i++) {
272
    for ( my $i = 0 ; $i <= $#subfields ; $i++ ) {
216
        my $code = $subfields[$i]->[0];
273
        my $code    = $subfields[$i]->[0];
217
        my $code_re = quotemeta $code;
274
        my $code_re = quotemeta $code;
218
        my $value = $subfields[$i]->[1];
275
        my $value   = $subfields[$i]->[1];
219
        next unless $subfields =~ qr/$code_re/;
276
        next unless $subfields =~ qr/$code_re/;
220
        if ($first) {
277
        if ($first) {
221
            $first = 0;
278
            $first   = 0;
222
            $heading = $value;
279
            $heading = $value;
223
        } else {
280
        }
224
            if (exists $subdivisions{$code}) {
281
        else {
282
            if ( exists $subdivisions{$code} ) {
225
                $heading .= "--$value";
283
                $heading .= "--$value";
226
            } else {
284
            }
285
            else {
227
                $heading .= " $value";
286
                $heading .= " $value";
228
            }
287
            }
229
        }
288
        }
Lines 231-236 sub _get_display_heading { Link Here
231
    return $heading;
290
    return $heading;
232
}
291
}
233
292
293
# Additional limiters that we aren't using:
294
#    if ($self->{'subject_added_entry'}) {
295
#        $limiters .= " AND Heading-use-subject-added-entry=a";
296
#    }
297
#    if ($self->{'series_added_entry'}) {
298
#        $limiters .= " AND Heading-use-series-added-entry=a";
299
#    }
300
#    if (not $self->{'subject_added_entry'} and not $self->{'series_added_entry'}) {
301
#        $limiters .= " AND Heading-use-main-or-added-entry=a"
302
#    }
303
234
=head1 AUTHOR
304
=head1 AUTHOR
235
305
236
Koha Development Team <http://koha-community.org/>
306
Koha Development Team <http://koha-community.org/>
(-)a/C4/Heading/UNIMARC.pm (+207 lines)
Line 0 Link Here
1
package C4::Heading::UNIMARC;
2
3
# Copyright (C) 2011 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use 5.010;
21
use strict;
22
use warnings;
23
use MARC::Record;
24
use MARC::Field;
25
use C4::Context;
26
27
our $VERSION = 3.00;
28
29
=head1 NAME
30
31
C4::Heading::UNIMARC
32
33
=head1 SYNOPSIS
34
35
use C4::Heading::UNIMARC;
36
37
=head1 DESCRIPTION
38
39
This is an internal helper class used by
40
C<C4::Heading> to parse headings data from
41
UNIMARC records.  Object of this type
42
do not carry data, instead, they only
43
dispatch functions.
44
45
=head1 DATA STRUCTURES
46
47
FIXME - this should be moved to a configuration file.
48
49
=head2 subdivisions
50
51
=cut
52
53
my %subdivisions = (
54
    'j' => 'formsubdiv',
55
    'x' => 'generalsubdiv',
56
    'y' => 'chronologicalsubdiv',
57
    'z' => 'geographicsubdiv',
58
);
59
60
my $bib_heading_fields;
61
62
BEGIN {
63
    my $dbh = C4::Context->dbh;
64
    my $sth = $dbh->prepare(
65
        "SELECT tagfield, authtypecode
66
         FROM marc_subfield_structure
67
         WHERE frameworkcode = '' AND authtypecode <> ''"
68
    );
69
    $sth->execute();
70
    $bib_heading_fields = {};
71
    while ( my ( $tag, $auth_type ) = $sth->fetchrow ) {
72
        $bib_heading_fields->{$tag} = {
73
            auth_type => $auth_type,
74
            subfields => 'abcdefghjklmnopqrstvxyz',
75
        };
76
    }
77
}
78
79
=head1 METHODS
80
81
=head2 new
82
83
  my $marc_handler = C4::Heading::UNIMARC->new();
84
85
=cut
86
87
sub new {
88
    my $class = shift;
89
    return bless {}, $class;
90
}
91
92
=head2 valid_bib_heading_tag
93
94
=cut
95
96
sub valid_bib_heading_tag {
97
    my ( $self, $tag ) = @_;
98
    return $bib_heading_fields->{$tag};
99
}
100
101
=head2 parse_heading
102
103
=cut
104
105
sub parse_heading {
106
    my ( $self, $field ) = @_;
107
108
    my $tag        = $field->tag;
109
    my $field_info = $bib_heading_fields->{$tag};
110
    my $auth_type  = $field_info->{'auth_type'};
111
    my $search_heading =
112
      _get_search_heading( $field, $field_info->{'subfields'} );
113
    my $display_heading =
114
      _get_display_heading( $field, $field_info->{'subfields'} );
115
116
    return ( $auth_type, undef, $search_heading, $display_heading, 'exact' );
117
}
118
119
=head1 INTERNAL FUNCTIONS
120
121
=head2 _get_subject_thesaurus
122
123
=cut
124
125
sub _get_subject_thesaurus {
126
    my $field = shift;
127
128
    my $thesaurus = "notdefined";
129
    my $sf2       = $field->subfield('2');
130
    $thesaurus = $sf2 if defined($sf2);
131
132
    return $thesaurus;
133
}
134
135
=head2 _get_search_heading
136
137
=cut
138
139
sub _get_search_heading {
140
    my $field     = shift;
141
    my $subfields = shift;
142
143
    my $heading   = "";
144
    my @subfields = $field->subfields();
145
    my $first     = 1;
146
    for ( my $i = 0 ; $i <= $#subfields ; $i++ ) {
147
        my $code    = $subfields[$i]->[0];
148
        my $code_re = quotemeta $code;
149
        my $value   = $subfields[$i]->[1];
150
        $value =~ s/[-,.:=;!%\/]*$//;
151
        next unless $subfields =~ qr/$code_re/;
152
        if ($first) {
153
            $first   = 0;
154
            $heading = $value;
155
        }
156
        else {
157
            $heading .= " $value";
158
        }
159
    }
160
161
    # remove characters that are part of CCL syntax
162
    $heading =~ s/[)(=]//g;
163
164
    return $heading;
165
}
166
167
=head2 _get_display_heading
168
169
=cut
170
171
sub _get_display_heading {
172
    my $field     = shift;
173
    my $subfields = shift;
174
175
    my $heading   = "";
176
    my @subfields = $field->subfields();
177
    my $first     = 1;
178
    for ( my $i = 0 ; $i <= $#subfields ; $i++ ) {
179
        my $code    = $subfields[$i]->[0];
180
        my $code_re = quotemeta $code;
181
        my $value   = $subfields[$i]->[1];
182
        next unless $subfields =~ qr/$code_re/;
183
        if ($first) {
184
            $first   = 0;
185
            $heading = $value;
186
        }
187
        else {
188
            if ( exists $subdivisions{$code} ) {
189
                $heading .= "--$value";
190
            }
191
            else {
192
                $heading .= " $value";
193
            }
194
        }
195
    }
196
    return $heading;
197
}
198
199
=head1 AUTHOR
200
201
Koha Development Team <http://koha-community.org/>
202
203
Jared Camins-Esakov <jcamins@cpbibliography.com>
204
205
=cut
206
207
1;
(-)a/C4/Linker.pm (+123 lines)
Line 0 Link Here
1
package C4::Linker;
2
3
# Copyright 2011 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
=head1 NAME
21
22
C4::Linker - Base class for linking authorities to bibliographic records
23
24
=head1 SYNOPSIS
25
26
  use C4::Linker (%params );
27
28
=head1 DESCRIPTION
29
30
Base class for C4::Linker::X. Subclasses need to provide the following methods
31
32
B<get_link ($field)> - return the authid for the authority that should be
33
linked to the provided MARC::Field object, and a boolean to indicate whether
34
the match is "fuzzy" (the semantics of "fuzzy" are up to the individual plugin).
35
In order to handle authority limits, get_link should always end with:
36
    return $self->SUPER::_handle_auth_limit($authid), $fuzzy;
37
38
B<flip_heading ($field)> - return a MARC::Field object with the heading flipped
39
to the preferred form.
40
41
=head1 FUNCTIONS
42
43
=cut
44
45
use strict;
46
use warnings;
47
use Carp;
48
use C4::Context;
49
50
use base qw(Class::Accessor);
51
52
__PACKAGE__->mk_accessors(qw( ));
53
54
sub new {
55
    my $class = shift;
56
    my $param = shift;
57
58
    my $self = {};
59
60
    while ( my ( $key, $value ) = each %$param ) {
61
        if ( $key eq 'auth_limit' && $value ) {
62
            my $dbh = C4::Context->dbh;
63
            my $sql =
64
              "SELECT authid FROM auth_header WHERE $value ORDER BY authid ASC";
65
            my $sth = $dbh->prepare($sql);
66
            $sth->execute();
67
            while ( my ($authid) = $sth->fetchrow_array() ) {
68
                push @{ $self->{'auths_to_link'} }, $authid;
69
            }
70
        }
71
        elsif ( $key eq 'options' && $value ) {
72
            foreach my $opt ( split( /\|/, $value ) ) {
73
                $self->{$opt} = 1;
74
            }
75
        }
76
        elsif ($value) {
77
            $self->{$key} = $value;
78
        }
79
    }
80
81
    bless $self, $class;
82
    return $self;
83
}
84
85
=head2 _handle_auth_limit
86
87
    return $self->SUPER::_handle_auth_limit($authid), $fuzzy;
88
89
=back
90
91
Function to be called by subclasses to handle authority record limits.
92
93
=cut
94
95
sub _handle_auth_limit {
96
    my $self   = shift;
97
    my $authid = shift;
98
99
    if ( defined $self->{'auths_to_link'} && defined $authid && !grep { $_ == $authid }
100
        @{ $self->{'auths_to_link'} } )
101
    {
102
        undef $authid;
103
    }
104
    return $authid;
105
}
106
107
=head2 EXPORT
108
109
None by default.
110
111
=head1 SEE ALSO
112
113
C4::Linker::Default
114
115
=head1 AUTHOR
116
117
Jared Camins-Esakov, C & P Bibliography Services, E<lt>jcamins@cpbibliography.comE<gt>
118
119
=cut
120
121
1;
122
123
__END__
(-)a/C4/Linker/Default.pm (+97 lines)
Line 0 Link Here
1
package C4::Linker::Default;
2
3
# Copyright 2011 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use Carp;
23
use MARC::Field;
24
use C4::Heading;
25
26
use base qw(C4::Linker);
27
28
sub get_link {
29
    my $self        = shift;
30
    my $heading     = shift;
31
    my $behavior    = shift || 'default';
32
    my $search_form = $heading->search_form();
33
    my $authid;
34
    my $fuzzy = 0;
35
36
    if ( $self->{'cache'}->{$search_form}->{'cached'} ) {
37
        $authid = $self->{'cache'}->{$search_form}->{'authid'};
38
        $fuzzy  = $self->{'cache'}->{$search_form}->{'fuzzy'};
39
    }
40
    else {
41
42
        # look for matching authorities
43
        my $authorities = $heading->authorities(1);    # $skipmetadata = true
44
45
        if ( $behavior eq 'default' && $#{$authorities} == 0 ) {
46
            $authid = $authorities->[0]->{'authid'};
47
        }
48
        elsif ( $behavior eq 'first' && $#{$authorities} >= 0 ) {
49
            $authid = $authorities->[0]->{'authid'};
50
            $fuzzy  = $#{$authorities} > 0;
51
        }
52
        elsif ( $behavior eq 'last' && $#{$authorities} >= 0 ) {
53
            $authid = $authorities->[ $#{$authorities} ]->{'authid'};
54
            $fuzzy  = $#{$authorities} > 0;
55
        }
56
57
        if ( !defined $authid && $self->{'broader_headings'} ) {
58
            my $field     = $heading->field();
59
            my @subfields = $field->subfields();
60
            if ( scalar @subfields > 1 ) {
61
                pop @subfields;
62
                $field->replace_with(
63
                    MARC::Field->new(
64
                        $field->tag,
65
                        $field->indicator(1),
66
                        $field->indicator(2),
67
                        map { $_[0] => $_[1] } @subfields
68
                    )
69
                );
70
                ( $authid, $fuzzy ) =
71
                  $self->get_link( C4::Heading->new_from_bib_field($field),
72
                    $behavior );
73
            }
74
        }
75
76
        $self->{'cache'}->{$search_form}->{'cached'} = 1;
77
        $self->{'cache'}->{$search_form}->{'authid'} = $authid;
78
        $self->{'cache'}->{$search_form}->{'fuzzy'}  = $fuzzy;
79
    }
80
    return $self->SUPER::_handle_auth_limit($authid), $fuzzy;
81
}
82
83
sub flip_heading {
84
    my $self    = shift;
85
    my $heading = shift;
86
87
    # TODO: implement
88
}
89
90
1;
91
__END__
92
93
=head1 NAME
94
95
C4::Linker::Default - match only if there is a single matching auth
96
97
=cut
(-)a/C4/Linker/FirstMatch.pm (+58 lines)
Line 0 Link Here
1
package C4::Linker::FirstMatch;
2
3
# Copyright 2011 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use Carp;
23
use C4::Heading;
24
use C4::Linker::Default;    # Use Default for flipping
25
26
use base qw(C4::Linker);
27
28
sub new {
29
    my $class = shift;
30
    my $param = shift;
31
32
    my $self = $class->SUPER::new($param);
33
    $self->{'default_linker'} = C4::Linker::Default->new($param);
34
    bless $self, $class;
35
    return $self;
36
}
37
38
sub get_link {
39
    my $self    = shift;
40
    my $heading = shift;
41
    return $self->{'default_linker'}->get_link( $heading, 'first' );
42
}
43
44
sub flip_heading {
45
    my $self    = shift;
46
    my $heading = shift;
47
48
    return $self->{'default_linker'}->flip($heading);
49
}
50
51
1;
52
__END__
53
54
=head1 NAME
55
56
C4::Linker::FirstMatch - match against the first authority record
57
58
=cut
(-)a/C4/Linker/LastMatch.pm (+58 lines)
Line 0 Link Here
1
package C4::Linker::LastMatch;
2
3
# Copyright 2011 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use Carp;
23
use C4::Heading;
24
use C4::Linker::Default;    # Use Default for flipping
25
26
use base qw(C4::Linker);
27
28
sub new {
29
    my $class = shift;
30
    my $param = shift;
31
32
    my $self = $class->SUPER::new($param);
33
    $self->{'default_linker'} = C4::Linker::Default->new($param);
34
    bless $self, $class;
35
    return $self;
36
}
37
38
sub get_link {
39
    my $self    = shift;
40
    my $heading = shift;
41
    return $self->{'default_linker'}->get_link( $heading, 'last' );
42
}
43
44
sub flip_heading {
45
    my $self    = shift;
46
    my $heading = shift;
47
48
    return $self->{'default_linker'}->flip($heading);
49
}
50
51
1;
52
__END__
53
54
=head1 NAME
55
56
C4::Linker::LastMatch - match against the last authority record
57
58
=cut
(-)a/C4/Search.pm (-101 lines)
Lines 70-79 This module provides searching functions for Koha's bibliographic databases Link Here
70
  &NZgetRecords
70
  &NZgetRecords
71
  &AddSearchHistory
71
  &AddSearchHistory
72
  &GetDistinctValues
72
  &GetDistinctValues
73
  &BiblioAddAuthorities
74
  &enabled_staff_search_views
73
  &enabled_staff_search_views
75
);
74
);
76
#FIXME: i had to add BiblioAddAuthorities here because in Biblios.pm it caused circular dependencies (C4::Search uses C4::Biblio, and BiblioAddAuthorities uses SimpleSearch from C4::Search)
77
75
78
# make all your functions, whether exported or not;
76
# make all your functions, whether exported or not;
79
77
Lines 2657-2761 sub z3950_search_args { Link Here
2657
    return $array;
2655
    return $array;
2658
}
2656
}
2659
2657
2660
=head2 BiblioAddAuthorities
2661
2662
( $countlinked, $countcreated ) = BiblioAddAuthorities($record, $frameworkcode);
2663
2664
this function finds the authorities linked to the biblio
2665
    * search in the authority DB for the same authid (in $9 of the biblio)
2666
    * search in the authority DB for the same 001 (in $3 of the biblio in UNIMARC)
2667
    * search in the authority DB for the same values (exactly) (in all subfields of the biblio)
2668
OR adds a new authority record
2669
2670
=over 2
2671
2672
=item C<input arg:>
2673
2674
    * $record is the MARC record in question (marc blob)
2675
    * $frameworkcode is the bibliographic framework to use (if it is "" it uses the default framework)
2676
2677
=item C<Output arg:>
2678
2679
    * $countlinked is the number of authorities records that are linked to this authority
2680
    * $countcreated
2681
2682
=item C<BUGS>
2683
    * I had to add this to Search.pm (instead of the logical Biblio.pm) because of a circular dependency (this sub uses SimpleSearch, and Search.pm uses Biblio.pm)
2684
2685
=back
2686
2687
=cut
2688
2689
2690
sub BiblioAddAuthorities{
2691
  my ( $record, $frameworkcode ) = @_;
2692
  my $dbh=C4::Context->dbh;
2693
  my $query=$dbh->prepare(qq|
2694
SELECT authtypecode,tagfield
2695
FROM marc_subfield_structure
2696
WHERE frameworkcode=?
2697
AND (authtypecode IS NOT NULL AND authtypecode<>\"\")|);
2698
# SELECT authtypecode,tagfield
2699
# FROM marc_subfield_structure
2700
# WHERE frameworkcode=?
2701
# AND (authtypecode IS NOT NULL OR authtypecode<>\"\")|);
2702
  $query->execute($frameworkcode);
2703
  my ($countcreated,$countlinked);
2704
  while (my $data=$query->fetchrow_hashref){
2705
    foreach my $field ($record->field($data->{tagfield})){
2706
      next if ($field->subfield('3')||$field->subfield('9'));
2707
      # No authorities id in the tag.
2708
      # Search if there is any authorities to link to.
2709
      my $query='at='.$data->{authtypecode}.' ';
2710
      map {$query.= ' and he,ext="'.$_->[1].'"' if ($_->[0]=~/[A-z]/)}  $field->subfields();
2711
      my ($error, $results, $total_hits)=SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
2712
    # there is only 1 result
2713
          if ( $error ) {
2714
        warn "BIBLIOADDSAUTHORITIES: $error";
2715
            return (0,0) ;
2716
          }
2717
      if ( @{$results} == 1 ) {
2718
        my $marcrecord = MARC::File::USMARC::decode($results->[0]);
2719
        $field->add_subfields('9'=>$marcrecord->field('001')->data);
2720
        $countlinked++;
2721
      } elsif ( @{$results} > 1 ) {
2722
   #More than One result
2723
   #This can comes out of a lack of a subfield.
2724
#         my $marcrecord = MARC::File::USMARC::decode($results->[0]);
2725
#         $record->field($data->{tagfield})->add_subfields('9'=>$marcrecord->field('001')->data);
2726
  $countlinked++;
2727
      } else {
2728
  #There are no results, build authority record, add it to Authorities, get authid and add it to 9
2729
  ###NOTICE : This is only valid if a subfield is linked to one and only one authtypecode
2730
  ###NOTICE : This can be a problem. We should also look into other types and rejected forms.
2731
         my $authtypedata=C4::AuthoritiesMarc::GetAuthType($data->{authtypecode});
2732
         next unless $authtypedata;
2733
         my $marcrecordauth=MARC::Record->new();
2734
         my $authfield=MARC::Field->new($authtypedata->{auth_tag_to_report},'','',"a"=>"".$field->subfield('a'));
2735
         map { $authfield->add_subfields($_->[0]=>$_->[1]) if ($_->[0]=~/[A-z]/ && $_->[0] ne "a" )}  $field->subfields();
2736
         $marcrecordauth->insert_fields_ordered($authfield);
2737
2738
         # bug 2317: ensure new authority knows it's using UTF-8; currently
2739
         # only need to do this for MARC21, as MARC::Record->as_xml_record() handles
2740
         # automatically for UNIMARC (by not transcoding)
2741
         # FIXME: AddAuthority() instead should simply explicitly require that the MARC::Record
2742
         # use UTF-8, but as of 2008-08-05, did not want to introduce that kind
2743
         # of change to a core API just before the 3.0 release.
2744
         if (C4::Context->preference('marcflavour') eq 'MARC21') {
2745
            SetMarcUnicodeFlag($marcrecordauth, 'MARC21');
2746
         }
2747
2748
#          warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
2749
2750
         my $authid=AddAuthority($marcrecordauth,'',$data->{authtypecode});
2751
         $countcreated++;
2752
         $field->add_subfields('9'=>$authid);
2753
      }
2754
    }
2755
  }
2756
  return ($countlinked,$countcreated);
2757
}
2758
2759
=head2 GetDistinctValues($field);
2658
=head2 GetDistinctValues($field);
2760
2659
2761
C<$field> is a reference to the fields array
2660
C<$field> is a reference to the fields array
(-)a/acqui/addorderiso2709.pl (-2 / +2 lines)
Lines 33-39 use C4::Input; Link Here
33
use C4::Output;
33
use C4::Output;
34
use C4::ImportBatch;
34
use C4::ImportBatch;
35
use C4::Matcher;
35
use C4::Matcher;
36
use C4::Search qw/FindDuplicate BiblioAddAuthorities/;
36
use C4::Search qw/FindDuplicate/;
37
use C4::Acquisition;
37
use C4::Acquisition;
38
use C4::Biblio;
38
use C4::Biblio;
39
use C4::Items;
39
use C4::Items;
Lines 183-189 if ($op eq ""){ Link Here
183
            SetImportRecordStatus( $biblio->{'import_record_id'}, 'imported' );
183
            SetImportRecordStatus( $biblio->{'import_record_id'}, 'imported' );
184
            # 2nd add authorities if applicable
184
            # 2nd add authorities if applicable
185
            if (C4::Context->preference("BiblioAddsAuthorities")){
185
            if (C4::Context->preference("BiblioAddsAuthorities")){
186
                my ($countlinked,$countcreated)=BiblioAddAuthorities($marcrecord, $cgiparams->{'frameworkcode'});
186
                my $headings_linked =BiblioAutoLink($marcrecord, $cgiparams->{'frameworkcode'});
187
            }
187
            }
188
        } else {
188
        } else {
189
            SetImportRecordStatus( $biblio->{'import_record_id'}, 'imported' );
189
            SetImportRecordStatus( $biblio->{'import_record_id'}, 'imported' );
(-)a/acqui/neworderempty.pl (-2 / +2 lines)
Lines 87-93 use C4::Input; Link Here
87
use C4::Koha;
87
use C4::Koha;
88
use C4::Branch;			# GetBranches
88
use C4::Branch;			# GetBranches
89
use C4::Members;
89
use C4::Members;
90
use C4::Search qw/FindDuplicate BiblioAddAuthorities/;
90
use C4::Search qw/FindDuplicate/;
91
91
92
#needed for z3950 import:
92
#needed for z3950 import:
93
use C4::ImportBatch qw/GetImportRecordMarc SetImportRecordStatus/;
93
use C4::ImportBatch qw/GetImportRecordMarc SetImportRecordStatus/;
Lines 150-156 if ( $ordernumber eq '' and defined $params->{'breedingid'}){ Link Here
150
    }
150
    }
151
    #from this point: add a new record
151
    #from this point: add a new record
152
        if (C4::Context->preference("BiblioAddsAuthorities")){
152
        if (C4::Context->preference("BiblioAddsAuthorities")){
153
            my ($countlinked,$countcreated)=BiblioAddAuthorities($marcrecord, $params->{'frameworkcode'});
153
            my $headings_linked=BiblioAutoLink($marcrecord, $params->{'frameworkcode'});
154
        }
154
        }
155
        my $bibitemnum;
155
        my $bibitemnum;
156
        $params->{'frameworkcode'} or $params->{'frameworkcode'} = "";
156
        $params->{'frameworkcode'} or $params->{'frameworkcode'} = "";
(-)a/authorities/auth_finder.pl (-4 / +4 lines)
Lines 60-66 if ( $op eq "do_search" ) { Link Here
60
    my @and_or    = $query->param('and_or');
60
    my @and_or    = $query->param('and_or');
61
    my @excluding = $query->param('excluding');
61
    my @excluding = $query->param('excluding');
62
    my @operator  = $query->param('operator');
62
    my @operator  = $query->param('operator');
63
    my @value     = ($query->param('value_mainstr')||undef, $query->param('value_main')||undef, $query->param('value_any')||undef);
63
    my @value     = ($query->param('value_mainstr')||undef, $query->param('value_main')||undef, $query->param('value_any')||undef, $query->param('value_match')||undef);
64
    my $orderby   = $query->param('orderby');
64
    my $orderby   = $query->param('orderby');
65
65
66
    $resultsperpage = $query->param('resultsperpage');
66
    $resultsperpage = $query->param('resultsperpage');
Lines 106-111 if ( $op eq "do_search" ) { Link Here
106
    push @field_data, { term => "value_mainstr", val => $query->param('value_mainstr') || "" };
106
    push @field_data, { term => "value_mainstr", val => $query->param('value_mainstr') || "" };
107
    push @field_data, { term => "value_main",    val => $query->param('value_main')    || "" };
107
    push @field_data, { term => "value_main",    val => $query->param('value_main')    || "" };
108
    push @field_data, { term => "value_any",     val => $query->param('value_any')     || ""};
108
    push @field_data, { term => "value_any",     val => $query->param('value_any')     || ""};
109
    push @field_data, { term => "value_match",   val => $query->param('value_match')   || ""};
109
110
110
    my @numbers = ();
111
    my @numbers = ();
111
112
Lines 162-167 if ( $op eq "do_search" ) { Link Here
162
        value_mainstr  => $query->param('value_mainstr') || "", 
163
        value_mainstr  => $query->param('value_mainstr') || "", 
163
        value_main     => $query->param('value_main') || "",
164
        value_main     => $query->param('value_main') || "",
164
        value_any      => $query->param('value_any') || "",
165
        value_any      => $query->param('value_any') || "",
166
        value_match    => $query->param('value_match') || "",
165
    );
167
    );
166
} else {
168
} else {
167
    ( $template, $loggedinuser, $cookie ) = get_template_and_user(
169
    ( $template, $loggedinuser, $cookie ) = get_template_and_user(
Lines 183-195 $template->param( Link Here
183
    value_mainstr => $query->param('value_mainstr') || "", 
185
    value_mainstr => $query->param('value_mainstr') || "", 
184
    value_main    => $query->param('value_main') || "",
186
    value_main    => $query->param('value_main') || "",
185
    value_any     => $query->param('value_any') || "",
187
    value_any     => $query->param('value_any') || "",
188
    value_match   => $query->param('value_match') || "",
186
    tagid         => $tagid,
189
    tagid         => $tagid,
187
    index         => $index,
190
    index         => $index,
188
    authtypesloop => \@authtypesloop,
191
    authtypesloop => \@authtypesloop,
189
    authtypecode  => $authtypecode,
192
    authtypecode  => $authtypecode,
190
    value_mainstr  => $query->param('value_mainstr') || "", 
191
    value_main     => $query->param('value_main')    || "",
192
    value_any      => $query->param('value_any')     || "",
193
);
193
);
194
194
195
# Print the page
195
# Print the page
(-)a/cataloguing/addbiblio.pl (-90 / +1 lines)
Lines 723-817 sub build_tabs { Link Here
723
    $template->param( BIG_LOOP => \@BIG_LOOP );
723
    $template->param( BIG_LOOP => \@BIG_LOOP );
724
}
724
}
725
725
726
#
727
# sub that tries to find authorities linked to the biblio
728
# the sub :
729
#   - search in the authority DB for the same authid (in $9 of the biblio)
730
#   - search in the authority DB for the same 001 (in $3 of the biblio in UNIMARC)
731
#   - search in the authority DB for the same values (exactly) (in all subfields of the biblio)
732
# if the authority is found, the biblio is modified accordingly to be connected to the authority.
733
# if the authority is not found, it's added, and the biblio is then modified to be connected to the authority.
734
#
735
736
sub BiblioAddAuthorities{
737
  my ( $record, $frameworkcode ) = @_;
738
  my $dbh=C4::Context->dbh;
739
  my $query=$dbh->prepare(qq|
740
SELECT authtypecode,tagfield
741
FROM marc_subfield_structure 
742
WHERE frameworkcode=? 
743
AND (authtypecode IS NOT NULL AND authtypecode<>\"\")|);
744
# SELECT authtypecode,tagfield
745
# FROM marc_subfield_structure 
746
# WHERE frameworkcode=? 
747
# AND (authtypecode IS NOT NULL OR authtypecode<>\"\")|);
748
  $query->execute($frameworkcode);
749
  my ($countcreated,$countlinked);
750
  while (my $data=$query->fetchrow_hashref){
751
    foreach my $field ($record->field($data->{tagfield})){
752
      next if ($field->subfield('3') || $field->subfield('9'));
753
      # No authorities id in the tag.
754
      # Search if there is any authorities to link to.
755
      my $query='at='.$data->{authtypecode}.' ';
756
      map {$query.= ' and he,ext="'.$_->[1].'"' if ($_->[0]=~/[A-z]/)}  $field->subfields();
757
      my ($error, $results, $total_hits)=SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
758
    # there is only 1 result 
759
	  if ( $error ) {
760
        warn "BIBLIOADDSAUTHORITIES: $error";
761
	    return (0,0) ;
762
	  }
763
      if ( @{$results} == 1) {
764
        my $marcrecord = MARC::File::USMARC::decode($results->[0]);
765
        $field->add_subfields('9'=>$marcrecord->field('001')->data);
766
        $countlinked++;
767
      } elsif (@{$results} > 1) {
768
   #More than One result 
769
   #This can comes out of a lack of a subfield.
770
#         my $marcrecord = MARC::File::USMARC::decode($results->[0]);
771
#         $record->field($data->{tagfield})->add_subfields('9'=>$marcrecord->field('001')->data);
772
        $countlinked++;
773
      } else {
774
  #There are no results, build authority record, add it to Authorities, get authid and add it to 9
775
  ###NOTICE : This is only valid if a subfield is linked to one and only one authtypecode     
776
  ###NOTICE : This can be a problem. We should also look into other types and rejected forms.
777
         my $authtypedata=GetAuthType($data->{authtypecode});
778
         next unless $authtypedata;
779
         my $marcrecordauth=MARC::Record->new();
780
		if (C4::Context->preference('marcflavour') eq 'MARC21') {
781
			$marcrecordauth->leader('     nz  a22     o  4500');
782
			SetMarcUnicodeFlag($marcrecordauth, 'MARC21');
783
			}
784
         my $authfield=MARC::Field->new($authtypedata->{auth_tag_to_report},'','',"a"=>"".$field->subfield('a'));
785
         map { $authfield->add_subfields($_->[0]=>$_->[1]) if ($_->[0]=~/[A-z]/ && $_->[0] ne "a" )}  $field->subfields();
786
         $marcrecordauth->insert_fields_ordered($authfield);
787
788
         # bug 2317: ensure new authority knows it's using UTF-8; currently
789
         # only need to do this for MARC21, as MARC::Record->as_xml_record() handles
790
         # automatically for UNIMARC (by not transcoding)
791
         # FIXME: AddAuthority() instead should simply explicitly require that the MARC::Record
792
         # use UTF-8, but as of 2008-08-05, did not want to introduce that kind
793
         # of change to a core API just before the 3.0 release.
794
795
				if (C4::Context->preference('marcflavour') eq 'MARC21') {
796
					$marcrecordauth->insert_fields_ordered(MARC::Field->new('667','','','a'=>"Machine generated authority record."));
797
					my $cite = $record->author() . ", " .  $record->title_proper() . ", " . $record->publication_date() . " "; 
798
					$cite =~ s/^[\s\,]*//;
799
					$cite =~ s/[\s\,]*$//;
800
					$cite = "Work cat.: (" . C4::Context->preference('MARCOrgCode') . ")". $record->subfield('999','c') . ": " . $cite;
801
					$marcrecordauth->insert_fields_ordered(MARC::Field->new('670','','','a'=>$cite));
802
				}
803
804
#          warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
805
806
         my $authid=AddAuthority($marcrecordauth,'',$data->{authtypecode});
807
         $countcreated++;
808
         $field->add_subfields('9'=>$authid);
809
      }
810
    }  
811
  }
812
  return ($countlinked,$countcreated);
813
}
814
815
# ========================
726
# ========================
816
#          MAIN
727
#          MAIN
817
#=========================
728
#=========================
Lines 944-950 if ( $op eq "addbiblio" ) { Link Here
944
        my $oldbibnum;
855
        my $oldbibnum;
945
        my $oldbibitemnum;
856
        my $oldbibitemnum;
946
        if (C4::Context->preference("BiblioAddsAuthorities")){
857
        if (C4::Context->preference("BiblioAddsAuthorities")){
947
          my ($countlinked,$countcreated)=BiblioAddAuthorities($record,$frameworkcode);
858
          my ($countlinked,$countcreated)=BiblioAutoLink($record,$frameworkcode);
948
        } 
859
        } 
949
        if ( $is_a_modif ) {
860
        if ( $is_a_modif ) {
950
            ModBiblioframework( $biblionumber, $frameworkcode ); 
861
            ModBiblioframework( $biblionumber, $frameworkcode ); 
(-)a/etc/zebradb/authorities/etc/bib1.att (+1 lines)
Lines 74-79 att 8807 Subdivision-see-also-from Link Here
74
att 8808    Subdivision-see-from
74
att 8808    Subdivision-see-from
75
att 8809    Match-heading-see-from
75
att 8809    Match-heading-see-from
76
att 8810    Match-subdivision-see-from
76
att 8810    Match-subdivision-see-from
77
att 8900    Match
77
78
78
# General Subdivision (defined in att 47)
79
# General Subdivision (defined in att 47)
79
att 9023    General-subdivision
80
att 9023    General-subdivision
(-)a/etc/zebradb/marc_defs/marc21/authorities/authority-koha-indexdefs.xml (+64 lines)
Lines 65-70 authority-zebra-indexdefs.xsl` Link Here
65
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
65
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
66
  </kohaidx:index_heading>
66
  </kohaidx:index_heading>
67
  <kohaidx:index_match_heading tag="100" subfields="abcdefghjklmnopqrstvxyz" subdivisions="vxyz">
67
  <kohaidx:index_match_heading tag="100" subfields="abcdefghjklmnopqrstvxyz" subdivisions="vxyz">
68
    <kohaidx:target_index>Match:w</kohaidx:target_index>
69
    <kohaidx:target_index>Match:p</kohaidx:target_index>
68
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
70
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
69
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
71
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
70
  </kohaidx:index_match_heading>
72
  </kohaidx:index_match_heading>
Lines 78-83 authority-zebra-indexdefs.xsl` Link Here
78
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
80
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
79
  </kohaidx:index_heading>
81
  </kohaidx:index_heading>
80
  <kohaidx:index_match_heading tag="400" subfields="abcdefghjklmnopqrstvxyz" subdivisions="vxyz">
82
  <kohaidx:index_match_heading tag="400" subfields="abcdefghjklmnopqrstvxyz" subdivisions="vxyz">
83
    <kohaidx:target_index>Match:w</kohaidx:target_index>
84
    <kohaidx:target_index>Match:p</kohaidx:target_index>
81
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
85
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
82
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
86
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
83
  </kohaidx:index_match_heading>
87
  </kohaidx:index_match_heading>
Lines 90-95 authority-zebra-indexdefs.xsl` Link Here
90
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
94
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
91
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
95
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
92
  </kohaidx:index_heading>
96
  </kohaidx:index_heading>
97
  <kohaidx:index_match_heading tag="500" subfields="abcdefghjklmnopqrstvxyz" subdivisions="vxyz">
98
    <kohaidx:target_index>Match:w</kohaidx:target_index>
99
    <kohaidx:target_index>Match:p</kohaidx:target_index>
100
  </kohaidx:index_match_heading>
93
  
101
  
94
  <!-- Corporate name headings -->
102
  <!-- Corporate name headings -->
95
  <kohaidx:index_subfields tag="110" subfields="abcdefghklmnoprstvxyz">
103
  <kohaidx:index_subfields tag="110" subfields="abcdefghklmnoprstvxyz">
Lines 110-115 authority-zebra-indexdefs.xsl` Link Here
110
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
118
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
111
  </kohaidx:index_heading>
119
  </kohaidx:index_heading>
112
  <kohaidx:index_match_heading tag="110" subfields="abcdefghklmnoprstvxyz" subdivisions="vxyz">
120
  <kohaidx:index_match_heading tag="110" subfields="abcdefghklmnoprstvxyz" subdivisions="vxyz">
121
    <kohaidx:target_index>Match:w</kohaidx:target_index>
122
    <kohaidx:target_index>Match:p</kohaidx:target_index>
113
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
123
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
114
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
124
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
115
  </kohaidx:index_match_heading>
125
  </kohaidx:index_match_heading>
Lines 123-128 authority-zebra-indexdefs.xsl` Link Here
123
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
133
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
124
  </kohaidx:index_heading>
134
  </kohaidx:index_heading>
125
  <kohaidx:index_match_heading tag="410" subfields="abcdefghklmnoprstvxyz" subdivisions="vxyz">
135
  <kohaidx:index_match_heading tag="410" subfields="abcdefghklmnoprstvxyz" subdivisions="vxyz">
136
    <kohaidx:target_index>Match:w</kohaidx:target_index>
137
    <kohaidx:target_index>Match:p</kohaidx:target_index>
126
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
138
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
127
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
139
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
128
  </kohaidx:index_match_heading>
140
  </kohaidx:index_match_heading>
Lines 135-140 authority-zebra-indexdefs.xsl` Link Here
135
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
147
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
136
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
148
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
137
  </kohaidx:index_heading>
149
  </kohaidx:index_heading>
150
  <kohaidx:index_match_heading tag="510" subfields="abcdefghklmnoprstvxyz" subdivisions="vxyz">
151
    <kohaidx:target_index>Match:w</kohaidx:target_index>
152
    <kohaidx:target_index>Match:p</kohaidx:target_index>
153
  </kohaidx:index_match_heading>
138
  
154
  
139
  <!-- Meeting name -->
155
  <!-- Meeting name -->
140
  <kohaidx:index_subfields tag="111" subfields="acdefghjklnpqstvxyz">
156
  <kohaidx:index_subfields tag="111" subfields="acdefghjklnpqstvxyz">
Lines 155-160 authority-zebra-indexdefs.xsl` Link Here
155
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
171
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
156
  </kohaidx:index_heading>
172
  </kohaidx:index_heading>
157
  <kohaidx:index_match_heading tag="111" subfields="acdefghjklnpqstvxyz" subdivisions="vxyz">
173
  <kohaidx:index_match_heading tag="111" subfields="acdefghjklnpqstvxyz" subdivisions="vxyz">
174
    <kohaidx:target_index>Match:w</kohaidx:target_index>
175
    <kohaidx:target_index>Match:p</kohaidx:target_index>
158
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
176
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
159
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
177
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
160
  </kohaidx:index_match_heading>
178
  </kohaidx:index_match_heading>
Lines 168-173 authority-zebra-indexdefs.xsl` Link Here
168
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
186
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
169
  </kohaidx:index_heading>
187
  </kohaidx:index_heading>
170
  <kohaidx:index_match_heading tag="411" subfields="acdefghjklnpqstvxyz" subdivisions="vxyz">
188
  <kohaidx:index_match_heading tag="411" subfields="acdefghjklnpqstvxyz" subdivisions="vxyz">
189
    <kohaidx:target_index>Match:w</kohaidx:target_index>
190
    <kohaidx:target_index>Match:p</kohaidx:target_index>
171
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
191
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
172
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
192
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
173
  </kohaidx:index_match_heading>
193
  </kohaidx:index_match_heading>
Lines 180-185 authority-zebra-indexdefs.xsl` Link Here
180
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
200
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
181
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
201
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
182
  </kohaidx:index_heading>
202
  </kohaidx:index_heading>
203
  <kohaidx:index_match_heading tag="511" subfields="acdefghjklnpqstvxyz" subdivisions="vxyz">
204
    <kohaidx:target_index>Match:w</kohaidx:target_index>
205
    <kohaidx:target_index>Match:p</kohaidx:target_index>
206
  </kohaidx:index_match_heading>
183
  
207
  
184
  <!-- Uniform title -->
208
  <!-- Uniform title -->
185
  <kohaidx:index_subfields tag="130" subfields="adfghklmnoprstvxyz">
209
  <kohaidx:index_subfields tag="130" subfields="adfghklmnoprstvxyz">
Lines 200-205 authority-zebra-indexdefs.xsl` Link Here
200
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
224
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
201
  </kohaidx:index_heading>
225
  </kohaidx:index_heading>
202
  <kohaidx:index_match_heading tag="130" subfields="adfghklmnoprstvxyz" subdivisions="vxyz">
226
  <kohaidx:index_match_heading tag="130" subfields="adfghklmnoprstvxyz" subdivisions="vxyz">
227
    <kohaidx:target_index>Match:w</kohaidx:target_index>
228
    <kohaidx:target_index>Match:p</kohaidx:target_index>
203
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
229
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
204
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
230
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
205
  </kohaidx:index_match_heading>
231
  </kohaidx:index_match_heading>
Lines 213-218 authority-zebra-indexdefs.xsl` Link Here
213
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
239
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
214
  </kohaidx:index_heading>
240
  </kohaidx:index_heading>
215
  <kohaidx:index_match_heading tag="430" subfields="adfghklmnoprstvxyz" subdivisions="vxyz">
241
  <kohaidx:index_match_heading tag="430" subfields="adfghklmnoprstvxyz" subdivisions="vxyz">
242
    <kohaidx:target_index>Match:w</kohaidx:target_index>
243
    <kohaidx:target_index>Match:p</kohaidx:target_index>
216
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
244
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
217
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
245
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
218
  </kohaidx:index_match_heading>
246
  </kohaidx:index_match_heading>
Lines 225-230 authority-zebra-indexdefs.xsl` Link Here
225
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
253
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
226
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
254
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
227
  </kohaidx:index_heading>
255
  </kohaidx:index_heading>
256
  <kohaidx:index_match_heading tag="530" subfields="adfghklmnoprstvxyz" subdivisions="vxyz">
257
    <kohaidx:target_index>Match:w</kohaidx:target_index>
258
    <kohaidx:target_index>Match:p</kohaidx:target_index>
259
  </kohaidx:index_match_heading>
228
  
260
  
229
  <!-- Chronological term -->
261
  <!-- Chronological term -->
230
  <kohaidx:index_subfields tag="148" subfields="avxyz">
262
  <kohaidx:index_subfields tag="148" subfields="avxyz">
Lines 245-250 authority-zebra-indexdefs.xsl` Link Here
245
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
277
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
246
  </kohaidx:index_heading>
278
  </kohaidx:index_heading>
247
  <kohaidx:index_match_heading tag="148" subfields="avxyz" subdivisions="vxyz">
279
  <kohaidx:index_match_heading tag="148" subfields="avxyz" subdivisions="vxyz">
280
    <kohaidx:target_index>Match:w</kohaidx:target_index>
281
    <kohaidx:target_index>Match:p</kohaidx:target_index>
248
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
282
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
249
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
283
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
250
  </kohaidx:index_match_heading>
284
  </kohaidx:index_match_heading>
Lines 258-263 authority-zebra-indexdefs.xsl` Link Here
258
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
292
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
259
  </kohaidx:index_heading>
293
  </kohaidx:index_heading>
260
  <kohaidx:index_match_heading tag="448" subfields="avxyz" subdivisions="vxyz">
294
  <kohaidx:index_match_heading tag="448" subfields="avxyz" subdivisions="vxyz">
295
    <kohaidx:target_index>Match:w</kohaidx:target_index>
296
    <kohaidx:target_index>Match:p</kohaidx:target_index>
261
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
297
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
262
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
298
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
263
  </kohaidx:index_match_heading>
299
  </kohaidx:index_match_heading>
Lines 270-275 authority-zebra-indexdefs.xsl` Link Here
270
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
306
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
271
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
307
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
272
  </kohaidx:index_heading>
308
  </kohaidx:index_heading>
309
  <kohaidx:index_match_heading tag="548" subfields="avxyz" subdivisions="vxyz">
310
    <kohaidx:target_index>Match:w</kohaidx:target_index>
311
    <kohaidx:target_index>Match:p</kohaidx:target_index>
312
  </kohaidx:index_match_heading>
273
  
313
  
274
  
314
  
275
  <!-- Topical term -->
315
  <!-- Topical term -->
Lines 291-296 authority-zebra-indexdefs.xsl` Link Here
291
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
331
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
292
  </kohaidx:index_heading>
332
  </kohaidx:index_heading>
293
  <kohaidx:index_match_heading tag="150" subfields="abvxyz" subdivisions="vxyz">
333
  <kohaidx:index_match_heading tag="150" subfields="abvxyz" subdivisions="vxyz">
334
    <kohaidx:target_index>Match:w</kohaidx:target_index>
335
    <kohaidx:target_index>Match:p</kohaidx:target_index>
294
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
336
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
295
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
337
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
296
  </kohaidx:index_match_heading>
338
  </kohaidx:index_match_heading>
Lines 304-309 authority-zebra-indexdefs.xsl` Link Here
304
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
346
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
305
  </kohaidx:index_heading>
347
  </kohaidx:index_heading>
306
  <kohaidx:index_match_heading tag="450" subfields="abvxyz" subdivisions="vxyz">
348
  <kohaidx:index_match_heading tag="450" subfields="abvxyz" subdivisions="vxyz">
349
    <kohaidx:target_index>Match:w</kohaidx:target_index>
350
    <kohaidx:target_index>Match:p</kohaidx:target_index>
307
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
351
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
308
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
352
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
309
  </kohaidx:index_match_heading>
353
  </kohaidx:index_match_heading>
Lines 316-321 authority-zebra-indexdefs.xsl` Link Here
316
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
360
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
317
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
361
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
318
  </kohaidx:index_heading>
362
  </kohaidx:index_heading>
363
  <kohaidx:index_match_heading tag="550" subfields="abvxyz" subdivisions="vxyz">
364
    <kohaidx:target_index>Match:w</kohaidx:target_index>
365
    <kohaidx:target_index>Match:p</kohaidx:target_index>
366
  </kohaidx:index_match_heading>
319
  
367
  
320
  <!-- Geographic name -->
368
  <!-- Geographic name -->
321
  <kohaidx:index_subfields tag="151" subfields="avxyz">
369
  <kohaidx:index_subfields tag="151" subfields="avxyz">
Lines 336-341 authority-zebra-indexdefs.xsl` Link Here
336
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
384
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
337
  </kohaidx:index_heading>
385
  </kohaidx:index_heading>
338
  <kohaidx:index_match_heading tag="151" subfields="avxyz" subdivisions="vxyz">
386
  <kohaidx:index_match_heading tag="151" subfields="avxyz" subdivisions="vxyz">
387
    <kohaidx:target_index>Match:w</kohaidx:target_index>
388
    <kohaidx:target_index>Match:p</kohaidx:target_index>
339
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
389
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
340
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
390
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
341
  </kohaidx:index_match_heading>
391
  </kohaidx:index_match_heading>
Lines 349-354 authority-zebra-indexdefs.xsl` Link Here
349
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
399
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
350
  </kohaidx:index_heading>
400
  </kohaidx:index_heading>
351
  <kohaidx:index_match_heading tag="451" subfields="avxyz" subdivisions="vxyz">
401
  <kohaidx:index_match_heading tag="451" subfields="avxyz" subdivisions="vxyz">
402
    <kohaidx:target_index>Match:w</kohaidx:target_index>
403
    <kohaidx:target_index>Match:p</kohaidx:target_index>
352
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
404
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
353
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
405
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
354
  </kohaidx:index_match_heading>
406
  </kohaidx:index_match_heading>
Lines 361-366 authority-zebra-indexdefs.xsl` Link Here
361
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
413
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
362
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
414
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
363
  </kohaidx:index_heading>
415
  </kohaidx:index_heading>
416
  <kohaidx:index_match_heading tag="551" subfields="avxyz" subdivisions="vxyz">
417
    <kohaidx:target_index>Match:w</kohaidx:target_index>
418
    <kohaidx:target_index>Match:p</kohaidx:target_index>
419
  </kohaidx:index_match_heading>
364
  
420
  
365
  <!-- Genre/form term -->
421
  <!-- Genre/form term -->
366
  <kohaidx:index_subfields tag="155" subfields="avxyz">
422
  <kohaidx:index_subfields tag="155" subfields="avxyz">
Lines 381-386 authority-zebra-indexdefs.xsl` Link Here
381
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
437
    <kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
382
  </kohaidx:index_heading>
438
  </kohaidx:index_heading>
383
  <kohaidx:index_match_heading tag="155" subfields="avxyz" subdivisions="vxyz">
439
  <kohaidx:index_match_heading tag="155" subfields="avxyz" subdivisions="vxyz">
440
    <kohaidx:target_index>Match:w</kohaidx:target_index>
441
    <kohaidx:target_index>Match:p</kohaidx:target_index>
384
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
442
    <kohaidx:target_index>Match-heading:p</kohaidx:target_index>
385
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
443
    <kohaidx:target_index>Match-heading:s</kohaidx:target_index>
386
  </kohaidx:index_match_heading>
444
  </kohaidx:index_match_heading>
Lines 394-399 authority-zebra-indexdefs.xsl` Link Here
394
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
452
    <kohaidx:target_index>See-from:s</kohaidx:target_index>
395
  </kohaidx:index_heading>
453
  </kohaidx:index_heading>
396
  <kohaidx:index_match_heading tag="455" subfields="avxyz" subdivisions="vxyz">
454
  <kohaidx:index_match_heading tag="455" subfields="avxyz" subdivisions="vxyz">
455
    <kohaidx:target_index>Match:w</kohaidx:target_index>
456
    <kohaidx:target_index>Match:p</kohaidx:target_index>
397
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
457
    <kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
398
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
458
    <kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
399
  </kohaidx:index_match_heading>
459
  </kohaidx:index_match_heading>
Lines 406-411 authority-zebra-indexdefs.xsl` Link Here
406
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
466
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
407
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
467
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
408
  </kohaidx:index_heading>
468
  </kohaidx:index_heading>
469
  <kohaidx:index_match_heading tag="555" subfields="avxyz" subdivisions="vxyz">
470
    <kohaidx:target_index>Match:w</kohaidx:target_index>
471
    <kohaidx:target_index>Match:p</kohaidx:target_index>
472
  </kohaidx:index_match_heading>
409
  
473
  
410
  <!-- General subdivision -->
474
  <!-- General subdivision -->
411
  <kohaidx:index_heading tag="180" subfields="vxyz" subdivisions="vxyz">
475
  <kohaidx:index_heading tag="180" subfields="vxyz" subdivisions="vxyz">
(-)a/etc/zebradb/marc_defs/marc21/authorities/authority-zebra-indexdefs.xsl (-56 / +481 lines)
Lines 1101-1110 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1101
    </z:index>
1101
    </z:index>
1102
  </xslo:template>
1102
  </xslo:template>
1103
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='100']">
1103
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='100']">
1104
    <z:index name="Match-heading:p Match-heading:s">
1104
    <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
1105
      <xslo:variable name="raw_heading">
1105
      <xslo:variable name="raw_heading">
1106
        <xslo:for-each select="marc:subfield">
1106
        <xslo:for-each select="marc:subfield">
1107
          <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match-heading:p Match-heading:s">
1107
          <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
1108
            <xslo:if test="position() &gt; 1">
1108
            <xslo:if test="position() &gt; 1">
1109
              <xslo:choose>
1109
              <xslo:choose>
1110
                <xslo:when test="contains('vxyz', @code)">
1110
                <xslo:when test="contains('vxyz', @code)">
Lines 1128-1134 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1128
                </xslo:otherwise>
1128
                </xslo:otherwise>
1129
              </xslo:choose>
1129
              </xslo:choose>
1130
            </xslo:if>
1130
            </xslo:if>
1131
            <xslo:value-of select="."/>
1131
            <xslo:call-template name="chopPunctuation">
1132
              <xslo:with-param name="chopString">
1133
                <xslo:value-of select="."/>
1134
              </xslo:with-param>
1135
            </xslo:call-template>
1132
          </xslo:if>
1136
          </xslo:if>
1133
        </xslo:for-each>
1137
        </xslo:for-each>
1134
      </xslo:variable>
1138
      </xslo:variable>
Lines 1136-1145 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1136
    </z:index>
1140
    </z:index>
1137
  </xslo:template>
1141
  </xslo:template>
1138
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='400']">
1142
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='400']">
1139
    <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
1143
    <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1140
      <xslo:variable name="raw_heading">
1144
      <xslo:variable name="raw_heading">
1141
        <xslo:for-each select="marc:subfield">
1145
        <xslo:for-each select="marc:subfield">
1142
          <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
1146
          <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1143
            <xslo:if test="position() &gt; 1">
1147
            <xslo:if test="position() &gt; 1">
1144
              <xslo:choose>
1148
              <xslo:choose>
1145
                <xslo:when test="contains('vxyz', @code)">
1149
                <xslo:when test="contains('vxyz', @code)">
Lines 1163-1169 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1163
                </xslo:otherwise>
1167
                </xslo:otherwise>
1164
              </xslo:choose>
1168
              </xslo:choose>
1165
            </xslo:if>
1169
            </xslo:if>
1166
            <xslo:value-of select="."/>
1170
            <xslo:call-template name="chopPunctuation">
1171
              <xslo:with-param name="chopString">
1172
                <xslo:value-of select="."/>
1173
              </xslo:with-param>
1174
            </xslo:call-template>
1175
          </xslo:if>
1176
        </xslo:for-each>
1177
      </xslo:variable>
1178
      <xslo:value-of select="normalize-space($raw_heading)"/>
1179
    </z:index>
1180
  </xslo:template>
1181
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='500']">
1182
    <z:index name="Match:w Match:p">
1183
      <xslo:variable name="raw_heading">
1184
        <xslo:for-each select="marc:subfield">
1185
          <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match:w Match:p">
1186
            <xslo:if test="position() &gt; 1">
1187
              <xslo:choose>
1188
                <xslo:when test="contains('vxyz', @code)">
1189
                  <xslo:choose>
1190
                    <xslo:when test="@code = $general_subdivision_subfield">
1191
                      <xslo:text> generalsubdiv </xslo:text>
1192
                    </xslo:when>
1193
                    <xslo:when test="@code = $form_subdivision_subfield">
1194
                      <xslo:text> formsubdiv </xslo:text>
1195
                    </xslo:when>
1196
                    <xslo:when test="@code = $chronological_subdivision_subfield">
1197
                      <xslo:text> chronologicalsubdiv </xslo:text>
1198
                    </xslo:when>
1199
                    <xslo:when test="@code = $geographic_subdivision_subfield">
1200
                      <xslo:text> geographicsubdiv </xslo:text>
1201
                    </xslo:when>
1202
                  </xslo:choose>
1203
                </xslo:when>
1204
                <xslo:otherwise>
1205
                  <xslo:value-of select="substring(' ', 1, 1)"/>
1206
                </xslo:otherwise>
1207
              </xslo:choose>
1208
            </xslo:if>
1209
            <xslo:call-template name="chopPunctuation">
1210
              <xslo:with-param name="chopString">
1211
                <xslo:value-of select="."/>
1212
              </xslo:with-param>
1213
            </xslo:call-template>
1167
          </xslo:if>
1214
          </xslo:if>
1168
        </xslo:for-each>
1215
        </xslo:for-each>
1169
      </xslo:variable>
1216
      </xslo:variable>
Lines 1171-1180 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1171
    </z:index>
1218
    </z:index>
1172
  </xslo:template>
1219
  </xslo:template>
1173
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='110']">
1220
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='110']">
1174
    <z:index name="Match-heading:p Match-heading:s">
1221
    <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
1175
      <xslo:variable name="raw_heading">
1222
      <xslo:variable name="raw_heading">
1176
        <xslo:for-each select="marc:subfield">
1223
        <xslo:for-each select="marc:subfield">
1177
          <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match-heading:p Match-heading:s">
1224
          <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
1178
            <xslo:if test="position() &gt; 1">
1225
            <xslo:if test="position() &gt; 1">
1179
              <xslo:choose>
1226
              <xslo:choose>
1180
                <xslo:when test="contains('vxyz', @code)">
1227
                <xslo:when test="contains('vxyz', @code)">
Lines 1198-1204 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1198
                </xslo:otherwise>
1245
                </xslo:otherwise>
1199
              </xslo:choose>
1246
              </xslo:choose>
1200
            </xslo:if>
1247
            </xslo:if>
1201
            <xslo:value-of select="."/>
1248
            <xslo:call-template name="chopPunctuation">
1249
              <xslo:with-param name="chopString">
1250
                <xslo:value-of select="."/>
1251
              </xslo:with-param>
1252
            </xslo:call-template>
1202
          </xslo:if>
1253
          </xslo:if>
1203
        </xslo:for-each>
1254
        </xslo:for-each>
1204
      </xslo:variable>
1255
      </xslo:variable>
Lines 1206-1215 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1206
    </z:index>
1257
    </z:index>
1207
  </xslo:template>
1258
  </xslo:template>
1208
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='410']">
1259
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='410']">
1209
    <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
1260
    <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1210
      <xslo:variable name="raw_heading">
1261
      <xslo:variable name="raw_heading">
1211
        <xslo:for-each select="marc:subfield">
1262
        <xslo:for-each select="marc:subfield">
1212
          <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
1263
          <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1213
            <xslo:if test="position() &gt; 1">
1264
            <xslo:if test="position() &gt; 1">
1214
              <xslo:choose>
1265
              <xslo:choose>
1215
                <xslo:when test="contains('vxyz', @code)">
1266
                <xslo:when test="contains('vxyz', @code)">
Lines 1233-1239 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1233
                </xslo:otherwise>
1284
                </xslo:otherwise>
1234
              </xslo:choose>
1285
              </xslo:choose>
1235
            </xslo:if>
1286
            </xslo:if>
1236
            <xslo:value-of select="."/>
1287
            <xslo:call-template name="chopPunctuation">
1288
              <xslo:with-param name="chopString">
1289
                <xslo:value-of select="."/>
1290
              </xslo:with-param>
1291
            </xslo:call-template>
1292
          </xslo:if>
1293
        </xslo:for-each>
1294
      </xslo:variable>
1295
      <xslo:value-of select="normalize-space($raw_heading)"/>
1296
    </z:index>
1297
  </xslo:template>
1298
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='510']">
1299
    <z:index name="Match:w Match:p">
1300
      <xslo:variable name="raw_heading">
1301
        <xslo:for-each select="marc:subfield">
1302
          <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match:w Match:p">
1303
            <xslo:if test="position() &gt; 1">
1304
              <xslo:choose>
1305
                <xslo:when test="contains('vxyz', @code)">
1306
                  <xslo:choose>
1307
                    <xslo:when test="@code = $general_subdivision_subfield">
1308
                      <xslo:text> generalsubdiv </xslo:text>
1309
                    </xslo:when>
1310
                    <xslo:when test="@code = $form_subdivision_subfield">
1311
                      <xslo:text> formsubdiv </xslo:text>
1312
                    </xslo:when>
1313
                    <xslo:when test="@code = $chronological_subdivision_subfield">
1314
                      <xslo:text> chronologicalsubdiv </xslo:text>
1315
                    </xslo:when>
1316
                    <xslo:when test="@code = $geographic_subdivision_subfield">
1317
                      <xslo:text> geographicsubdiv </xslo:text>
1318
                    </xslo:when>
1319
                  </xslo:choose>
1320
                </xslo:when>
1321
                <xslo:otherwise>
1322
                  <xslo:value-of select="substring(' ', 1, 1)"/>
1323
                </xslo:otherwise>
1324
              </xslo:choose>
1325
            </xslo:if>
1326
            <xslo:call-template name="chopPunctuation">
1327
              <xslo:with-param name="chopString">
1328
                <xslo:value-of select="."/>
1329
              </xslo:with-param>
1330
            </xslo:call-template>
1237
          </xslo:if>
1331
          </xslo:if>
1238
        </xslo:for-each>
1332
        </xslo:for-each>
1239
      </xslo:variable>
1333
      </xslo:variable>
Lines 1241-1250 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1241
    </z:index>
1335
    </z:index>
1242
  </xslo:template>
1336
  </xslo:template>
1243
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='111']">
1337
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='111']">
1244
    <z:index name="Match-heading:p Match-heading:s">
1338
    <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
1245
      <xslo:variable name="raw_heading">
1339
      <xslo:variable name="raw_heading">
1246
        <xslo:for-each select="marc:subfield">
1340
        <xslo:for-each select="marc:subfield">
1247
          <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match-heading:p Match-heading:s">
1341
          <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
1248
            <xslo:if test="position() &gt; 1">
1342
            <xslo:if test="position() &gt; 1">
1249
              <xslo:choose>
1343
              <xslo:choose>
1250
                <xslo:when test="contains('vxyz', @code)">
1344
                <xslo:when test="contains('vxyz', @code)">
Lines 1268-1274 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1268
                </xslo:otherwise>
1362
                </xslo:otherwise>
1269
              </xslo:choose>
1363
              </xslo:choose>
1270
            </xslo:if>
1364
            </xslo:if>
1271
            <xslo:value-of select="."/>
1365
            <xslo:call-template name="chopPunctuation">
1366
              <xslo:with-param name="chopString">
1367
                <xslo:value-of select="."/>
1368
              </xslo:with-param>
1369
            </xslo:call-template>
1272
          </xslo:if>
1370
          </xslo:if>
1273
        </xslo:for-each>
1371
        </xslo:for-each>
1274
      </xslo:variable>
1372
      </xslo:variable>
Lines 1276-1285 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1276
    </z:index>
1374
    </z:index>
1277
  </xslo:template>
1375
  </xslo:template>
1278
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='411']">
1376
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='411']">
1279
    <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
1377
    <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1280
      <xslo:variable name="raw_heading">
1378
      <xslo:variable name="raw_heading">
1281
        <xslo:for-each select="marc:subfield">
1379
        <xslo:for-each select="marc:subfield">
1282
          <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
1380
          <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1283
            <xslo:if test="position() &gt; 1">
1381
            <xslo:if test="position() &gt; 1">
1284
              <xslo:choose>
1382
              <xslo:choose>
1285
                <xslo:when test="contains('vxyz', @code)">
1383
                <xslo:when test="contains('vxyz', @code)">
Lines 1303-1309 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1303
                </xslo:otherwise>
1401
                </xslo:otherwise>
1304
              </xslo:choose>
1402
              </xslo:choose>
1305
            </xslo:if>
1403
            </xslo:if>
1306
            <xslo:value-of select="."/>
1404
            <xslo:call-template name="chopPunctuation">
1405
              <xslo:with-param name="chopString">
1406
                <xslo:value-of select="."/>
1407
              </xslo:with-param>
1408
            </xslo:call-template>
1409
          </xslo:if>
1410
        </xslo:for-each>
1411
      </xslo:variable>
1412
      <xslo:value-of select="normalize-space($raw_heading)"/>
1413
    </z:index>
1414
  </xslo:template>
1415
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='511']">
1416
    <z:index name="Match:w Match:p">
1417
      <xslo:variable name="raw_heading">
1418
        <xslo:for-each select="marc:subfield">
1419
          <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match:w Match:p">
1420
            <xslo:if test="position() &gt; 1">
1421
              <xslo:choose>
1422
                <xslo:when test="contains('vxyz', @code)">
1423
                  <xslo:choose>
1424
                    <xslo:when test="@code = $general_subdivision_subfield">
1425
                      <xslo:text> generalsubdiv </xslo:text>
1426
                    </xslo:when>
1427
                    <xslo:when test="@code = $form_subdivision_subfield">
1428
                      <xslo:text> formsubdiv </xslo:text>
1429
                    </xslo:when>
1430
                    <xslo:when test="@code = $chronological_subdivision_subfield">
1431
                      <xslo:text> chronologicalsubdiv </xslo:text>
1432
                    </xslo:when>
1433
                    <xslo:when test="@code = $geographic_subdivision_subfield">
1434
                      <xslo:text> geographicsubdiv </xslo:text>
1435
                    </xslo:when>
1436
                  </xslo:choose>
1437
                </xslo:when>
1438
                <xslo:otherwise>
1439
                  <xslo:value-of select="substring(' ', 1, 1)"/>
1440
                </xslo:otherwise>
1441
              </xslo:choose>
1442
            </xslo:if>
1443
            <xslo:call-template name="chopPunctuation">
1444
              <xslo:with-param name="chopString">
1445
                <xslo:value-of select="."/>
1446
              </xslo:with-param>
1447
            </xslo:call-template>
1307
          </xslo:if>
1448
          </xslo:if>
1308
        </xslo:for-each>
1449
        </xslo:for-each>
1309
      </xslo:variable>
1450
      </xslo:variable>
Lines 1311-1320 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1311
    </z:index>
1452
    </z:index>
1312
  </xslo:template>
1453
  </xslo:template>
1313
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='130']">
1454
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='130']">
1314
    <z:index name="Match-heading:p Match-heading:s">
1455
    <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
1315
      <xslo:variable name="raw_heading">
1456
      <xslo:variable name="raw_heading">
1316
        <xslo:for-each select="marc:subfield">
1457
        <xslo:for-each select="marc:subfield">
1317
          <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match-heading:p Match-heading:s">
1458
          <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
1318
            <xslo:if test="position() &gt; 1">
1459
            <xslo:if test="position() &gt; 1">
1319
              <xslo:choose>
1460
              <xslo:choose>
1320
                <xslo:when test="contains('vxyz', @code)">
1461
                <xslo:when test="contains('vxyz', @code)">
Lines 1338-1344 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1338
                </xslo:otherwise>
1479
                </xslo:otherwise>
1339
              </xslo:choose>
1480
              </xslo:choose>
1340
            </xslo:if>
1481
            </xslo:if>
1341
            <xslo:value-of select="."/>
1482
            <xslo:call-template name="chopPunctuation">
1483
              <xslo:with-param name="chopString">
1484
                <xslo:value-of select="."/>
1485
              </xslo:with-param>
1486
            </xslo:call-template>
1342
          </xslo:if>
1487
          </xslo:if>
1343
        </xslo:for-each>
1488
        </xslo:for-each>
1344
      </xslo:variable>
1489
      </xslo:variable>
Lines 1346-1355 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1346
    </z:index>
1491
    </z:index>
1347
  </xslo:template>
1492
  </xslo:template>
1348
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='430']">
1493
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='430']">
1349
    <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
1494
    <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1350
      <xslo:variable name="raw_heading">
1495
      <xslo:variable name="raw_heading">
1351
        <xslo:for-each select="marc:subfield">
1496
        <xslo:for-each select="marc:subfield">
1352
          <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
1497
          <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1353
            <xslo:if test="position() &gt; 1">
1498
            <xslo:if test="position() &gt; 1">
1354
              <xslo:choose>
1499
              <xslo:choose>
1355
                <xslo:when test="contains('vxyz', @code)">
1500
                <xslo:when test="contains('vxyz', @code)">
Lines 1373-1379 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1373
                </xslo:otherwise>
1518
                </xslo:otherwise>
1374
              </xslo:choose>
1519
              </xslo:choose>
1375
            </xslo:if>
1520
            </xslo:if>
1376
            <xslo:value-of select="."/>
1521
            <xslo:call-template name="chopPunctuation">
1522
              <xslo:with-param name="chopString">
1523
                <xslo:value-of select="."/>
1524
              </xslo:with-param>
1525
            </xslo:call-template>
1526
          </xslo:if>
1527
        </xslo:for-each>
1528
      </xslo:variable>
1529
      <xslo:value-of select="normalize-space($raw_heading)"/>
1530
    </z:index>
1531
  </xslo:template>
1532
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='530']">
1533
    <z:index name="Match:w Match:p">
1534
      <xslo:variable name="raw_heading">
1535
        <xslo:for-each select="marc:subfield">
1536
          <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match:w Match:p">
1537
            <xslo:if test="position() &gt; 1">
1538
              <xslo:choose>
1539
                <xslo:when test="contains('vxyz', @code)">
1540
                  <xslo:choose>
1541
                    <xslo:when test="@code = $general_subdivision_subfield">
1542
                      <xslo:text> generalsubdiv </xslo:text>
1543
                    </xslo:when>
1544
                    <xslo:when test="@code = $form_subdivision_subfield">
1545
                      <xslo:text> formsubdiv </xslo:text>
1546
                    </xslo:when>
1547
                    <xslo:when test="@code = $chronological_subdivision_subfield">
1548
                      <xslo:text> chronologicalsubdiv </xslo:text>
1549
                    </xslo:when>
1550
                    <xslo:when test="@code = $geographic_subdivision_subfield">
1551
                      <xslo:text> geographicsubdiv </xslo:text>
1552
                    </xslo:when>
1553
                  </xslo:choose>
1554
                </xslo:when>
1555
                <xslo:otherwise>
1556
                  <xslo:value-of select="substring(' ', 1, 1)"/>
1557
                </xslo:otherwise>
1558
              </xslo:choose>
1559
            </xslo:if>
1560
            <xslo:call-template name="chopPunctuation">
1561
              <xslo:with-param name="chopString">
1562
                <xslo:value-of select="."/>
1563
              </xslo:with-param>
1564
            </xslo:call-template>
1377
          </xslo:if>
1565
          </xslo:if>
1378
        </xslo:for-each>
1566
        </xslo:for-each>
1379
      </xslo:variable>
1567
      </xslo:variable>
Lines 1381-1390 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1381
    </z:index>
1569
    </z:index>
1382
  </xslo:template>
1570
  </xslo:template>
1383
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='148']">
1571
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='148']">
1384
    <z:index name="Match-heading:p Match-heading:s">
1572
    <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
1385
      <xslo:variable name="raw_heading">
1573
      <xslo:variable name="raw_heading">
1386
        <xslo:for-each select="marc:subfield">
1574
        <xslo:for-each select="marc:subfield">
1387
          <xslo:if test="contains('avxyz', @code)" name="Match-heading:p Match-heading:s">
1575
          <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
1388
            <xslo:if test="position() &gt; 1">
1576
            <xslo:if test="position() &gt; 1">
1389
              <xslo:choose>
1577
              <xslo:choose>
1390
                <xslo:when test="contains('vxyz', @code)">
1578
                <xslo:when test="contains('vxyz', @code)">
Lines 1408-1414 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1408
                </xslo:otherwise>
1596
                </xslo:otherwise>
1409
              </xslo:choose>
1597
              </xslo:choose>
1410
            </xslo:if>
1598
            </xslo:if>
1411
            <xslo:value-of select="."/>
1599
            <xslo:call-template name="chopPunctuation">
1600
              <xslo:with-param name="chopString">
1601
                <xslo:value-of select="."/>
1602
              </xslo:with-param>
1603
            </xslo:call-template>
1412
          </xslo:if>
1604
          </xslo:if>
1413
        </xslo:for-each>
1605
        </xslo:for-each>
1414
      </xslo:variable>
1606
      </xslo:variable>
Lines 1416-1425 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1416
    </z:index>
1608
    </z:index>
1417
  </xslo:template>
1609
  </xslo:template>
1418
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='448']">
1610
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='448']">
1419
    <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
1611
    <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1420
      <xslo:variable name="raw_heading">
1612
      <xslo:variable name="raw_heading">
1421
        <xslo:for-each select="marc:subfield">
1613
        <xslo:for-each select="marc:subfield">
1422
          <xslo:if test="contains('avxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
1614
          <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1423
            <xslo:if test="position() &gt; 1">
1615
            <xslo:if test="position() &gt; 1">
1424
              <xslo:choose>
1616
              <xslo:choose>
1425
                <xslo:when test="contains('vxyz', @code)">
1617
                <xslo:when test="contains('vxyz', @code)">
Lines 1443-1449 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1443
                </xslo:otherwise>
1635
                </xslo:otherwise>
1444
              </xslo:choose>
1636
              </xslo:choose>
1445
            </xslo:if>
1637
            </xslo:if>
1446
            <xslo:value-of select="."/>
1638
            <xslo:call-template name="chopPunctuation">
1639
              <xslo:with-param name="chopString">
1640
                <xslo:value-of select="."/>
1641
              </xslo:with-param>
1642
            </xslo:call-template>
1643
          </xslo:if>
1644
        </xslo:for-each>
1645
      </xslo:variable>
1646
      <xslo:value-of select="normalize-space($raw_heading)"/>
1647
    </z:index>
1648
  </xslo:template>
1649
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='548']">
1650
    <z:index name="Match:w Match:p">
1651
      <xslo:variable name="raw_heading">
1652
        <xslo:for-each select="marc:subfield">
1653
          <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p">
1654
            <xslo:if test="position() &gt; 1">
1655
              <xslo:choose>
1656
                <xslo:when test="contains('vxyz', @code)">
1657
                  <xslo:choose>
1658
                    <xslo:when test="@code = $general_subdivision_subfield">
1659
                      <xslo:text> generalsubdiv </xslo:text>
1660
                    </xslo:when>
1661
                    <xslo:when test="@code = $form_subdivision_subfield">
1662
                      <xslo:text> formsubdiv </xslo:text>
1663
                    </xslo:when>
1664
                    <xslo:when test="@code = $chronological_subdivision_subfield">
1665
                      <xslo:text> chronologicalsubdiv </xslo:text>
1666
                    </xslo:when>
1667
                    <xslo:when test="@code = $geographic_subdivision_subfield">
1668
                      <xslo:text> geographicsubdiv </xslo:text>
1669
                    </xslo:when>
1670
                  </xslo:choose>
1671
                </xslo:when>
1672
                <xslo:otherwise>
1673
                  <xslo:value-of select="substring(' ', 1, 1)"/>
1674
                </xslo:otherwise>
1675
              </xslo:choose>
1676
            </xslo:if>
1677
            <xslo:call-template name="chopPunctuation">
1678
              <xslo:with-param name="chopString">
1679
                <xslo:value-of select="."/>
1680
              </xslo:with-param>
1681
            </xslo:call-template>
1447
          </xslo:if>
1682
          </xslo:if>
1448
        </xslo:for-each>
1683
        </xslo:for-each>
1449
      </xslo:variable>
1684
      </xslo:variable>
Lines 1451-1460 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1451
    </z:index>
1686
    </z:index>
1452
  </xslo:template>
1687
  </xslo:template>
1453
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='150']">
1688
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='150']">
1454
    <z:index name="Match-heading:p Match-heading:s">
1689
    <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
1455
      <xslo:variable name="raw_heading">
1690
      <xslo:variable name="raw_heading">
1456
        <xslo:for-each select="marc:subfield">
1691
        <xslo:for-each select="marc:subfield">
1457
          <xslo:if test="contains('abvxyz', @code)" name="Match-heading:p Match-heading:s">
1692
          <xslo:if test="contains('abvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
1458
            <xslo:if test="position() &gt; 1">
1693
            <xslo:if test="position() &gt; 1">
1459
              <xslo:choose>
1694
              <xslo:choose>
1460
                <xslo:when test="contains('vxyz', @code)">
1695
                <xslo:when test="contains('vxyz', @code)">
Lines 1478-1484 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1478
                </xslo:otherwise>
1713
                </xslo:otherwise>
1479
              </xslo:choose>
1714
              </xslo:choose>
1480
            </xslo:if>
1715
            </xslo:if>
1481
            <xslo:value-of select="."/>
1716
            <xslo:call-template name="chopPunctuation">
1717
              <xslo:with-param name="chopString">
1718
                <xslo:value-of select="."/>
1719
              </xslo:with-param>
1720
            </xslo:call-template>
1482
          </xslo:if>
1721
          </xslo:if>
1483
        </xslo:for-each>
1722
        </xslo:for-each>
1484
      </xslo:variable>
1723
      </xslo:variable>
Lines 1486-1495 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1486
    </z:index>
1725
    </z:index>
1487
  </xslo:template>
1726
  </xslo:template>
1488
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='450']">
1727
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='450']">
1489
    <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
1728
    <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1490
      <xslo:variable name="raw_heading">
1729
      <xslo:variable name="raw_heading">
1491
        <xslo:for-each select="marc:subfield">
1730
        <xslo:for-each select="marc:subfield">
1492
          <xslo:if test="contains('abvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
1731
          <xslo:if test="contains('abvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1493
            <xslo:if test="position() &gt; 1">
1732
            <xslo:if test="position() &gt; 1">
1494
              <xslo:choose>
1733
              <xslo:choose>
1495
                <xslo:when test="contains('vxyz', @code)">
1734
                <xslo:when test="contains('vxyz', @code)">
Lines 1513-1519 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1513
                </xslo:otherwise>
1752
                </xslo:otherwise>
1514
              </xslo:choose>
1753
              </xslo:choose>
1515
            </xslo:if>
1754
            </xslo:if>
1516
            <xslo:value-of select="."/>
1755
            <xslo:call-template name="chopPunctuation">
1756
              <xslo:with-param name="chopString">
1757
                <xslo:value-of select="."/>
1758
              </xslo:with-param>
1759
            </xslo:call-template>
1760
          </xslo:if>
1761
        </xslo:for-each>
1762
      </xslo:variable>
1763
      <xslo:value-of select="normalize-space($raw_heading)"/>
1764
    </z:index>
1765
  </xslo:template>
1766
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='550']">
1767
    <z:index name="Match:w Match:p">
1768
      <xslo:variable name="raw_heading">
1769
        <xslo:for-each select="marc:subfield">
1770
          <xslo:if test="contains('abvxyz', @code)" name="Match:w Match:p">
1771
            <xslo:if test="position() &gt; 1">
1772
              <xslo:choose>
1773
                <xslo:when test="contains('vxyz', @code)">
1774
                  <xslo:choose>
1775
                    <xslo:when test="@code = $general_subdivision_subfield">
1776
                      <xslo:text> generalsubdiv </xslo:text>
1777
                    </xslo:when>
1778
                    <xslo:when test="@code = $form_subdivision_subfield">
1779
                      <xslo:text> formsubdiv </xslo:text>
1780
                    </xslo:when>
1781
                    <xslo:when test="@code = $chronological_subdivision_subfield">
1782
                      <xslo:text> chronologicalsubdiv </xslo:text>
1783
                    </xslo:when>
1784
                    <xslo:when test="@code = $geographic_subdivision_subfield">
1785
                      <xslo:text> geographicsubdiv </xslo:text>
1786
                    </xslo:when>
1787
                  </xslo:choose>
1788
                </xslo:when>
1789
                <xslo:otherwise>
1790
                  <xslo:value-of select="substring(' ', 1, 1)"/>
1791
                </xslo:otherwise>
1792
              </xslo:choose>
1793
            </xslo:if>
1794
            <xslo:call-template name="chopPunctuation">
1795
              <xslo:with-param name="chopString">
1796
                <xslo:value-of select="."/>
1797
              </xslo:with-param>
1798
            </xslo:call-template>
1517
          </xslo:if>
1799
          </xslo:if>
1518
        </xslo:for-each>
1800
        </xslo:for-each>
1519
      </xslo:variable>
1801
      </xslo:variable>
Lines 1521-1530 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1521
    </z:index>
1803
    </z:index>
1522
  </xslo:template>
1804
  </xslo:template>
1523
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='151']">
1805
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='151']">
1524
    <z:index name="Match-heading:p Match-heading:s">
1806
    <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
1525
      <xslo:variable name="raw_heading">
1807
      <xslo:variable name="raw_heading">
1526
        <xslo:for-each select="marc:subfield">
1808
        <xslo:for-each select="marc:subfield">
1527
          <xslo:if test="contains('avxyz', @code)" name="Match-heading:p Match-heading:s">
1809
          <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
1528
            <xslo:if test="position() &gt; 1">
1810
            <xslo:if test="position() &gt; 1">
1529
              <xslo:choose>
1811
              <xslo:choose>
1530
                <xslo:when test="contains('vxyz', @code)">
1812
                <xslo:when test="contains('vxyz', @code)">
Lines 1548-1554 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1548
                </xslo:otherwise>
1830
                </xslo:otherwise>
1549
              </xslo:choose>
1831
              </xslo:choose>
1550
            </xslo:if>
1832
            </xslo:if>
1551
            <xslo:value-of select="."/>
1833
            <xslo:call-template name="chopPunctuation">
1834
              <xslo:with-param name="chopString">
1835
                <xslo:value-of select="."/>
1836
              </xslo:with-param>
1837
            </xslo:call-template>
1552
          </xslo:if>
1838
          </xslo:if>
1553
        </xslo:for-each>
1839
        </xslo:for-each>
1554
      </xslo:variable>
1840
      </xslo:variable>
Lines 1556-1565 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1556
    </z:index>
1842
    </z:index>
1557
  </xslo:template>
1843
  </xslo:template>
1558
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='451']">
1844
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='451']">
1559
    <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
1845
    <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1560
      <xslo:variable name="raw_heading">
1846
      <xslo:variable name="raw_heading">
1561
        <xslo:for-each select="marc:subfield">
1847
        <xslo:for-each select="marc:subfield">
1562
          <xslo:if test="contains('avxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
1848
          <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1563
            <xslo:if test="position() &gt; 1">
1849
            <xslo:if test="position() &gt; 1">
1564
              <xslo:choose>
1850
              <xslo:choose>
1565
                <xslo:when test="contains('vxyz', @code)">
1851
                <xslo:when test="contains('vxyz', @code)">
Lines 1583-1589 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1583
                </xslo:otherwise>
1869
                </xslo:otherwise>
1584
              </xslo:choose>
1870
              </xslo:choose>
1585
            </xslo:if>
1871
            </xslo:if>
1586
            <xslo:value-of select="."/>
1872
            <xslo:call-template name="chopPunctuation">
1873
              <xslo:with-param name="chopString">
1874
                <xslo:value-of select="."/>
1875
              </xslo:with-param>
1876
            </xslo:call-template>
1877
          </xslo:if>
1878
        </xslo:for-each>
1879
      </xslo:variable>
1880
      <xslo:value-of select="normalize-space($raw_heading)"/>
1881
    </z:index>
1882
  </xslo:template>
1883
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='551']">
1884
    <z:index name="Match:w Match:p">
1885
      <xslo:variable name="raw_heading">
1886
        <xslo:for-each select="marc:subfield">
1887
          <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p">
1888
            <xslo:if test="position() &gt; 1">
1889
              <xslo:choose>
1890
                <xslo:when test="contains('vxyz', @code)">
1891
                  <xslo:choose>
1892
                    <xslo:when test="@code = $general_subdivision_subfield">
1893
                      <xslo:text> generalsubdiv </xslo:text>
1894
                    </xslo:when>
1895
                    <xslo:when test="@code = $form_subdivision_subfield">
1896
                      <xslo:text> formsubdiv </xslo:text>
1897
                    </xslo:when>
1898
                    <xslo:when test="@code = $chronological_subdivision_subfield">
1899
                      <xslo:text> chronologicalsubdiv </xslo:text>
1900
                    </xslo:when>
1901
                    <xslo:when test="@code = $geographic_subdivision_subfield">
1902
                      <xslo:text> geographicsubdiv </xslo:text>
1903
                    </xslo:when>
1904
                  </xslo:choose>
1905
                </xslo:when>
1906
                <xslo:otherwise>
1907
                  <xslo:value-of select="substring(' ', 1, 1)"/>
1908
                </xslo:otherwise>
1909
              </xslo:choose>
1910
            </xslo:if>
1911
            <xslo:call-template name="chopPunctuation">
1912
              <xslo:with-param name="chopString">
1913
                <xslo:value-of select="."/>
1914
              </xslo:with-param>
1915
            </xslo:call-template>
1587
          </xslo:if>
1916
          </xslo:if>
1588
        </xslo:for-each>
1917
        </xslo:for-each>
1589
      </xslo:variable>
1918
      </xslo:variable>
Lines 1591-1600 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1591
    </z:index>
1920
    </z:index>
1592
  </xslo:template>
1921
  </xslo:template>
1593
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='155']">
1922
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='155']">
1594
    <z:index name="Match-heading:p Match-heading:s">
1923
    <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
1595
      <xslo:variable name="raw_heading">
1924
      <xslo:variable name="raw_heading">
1596
        <xslo:for-each select="marc:subfield">
1925
        <xslo:for-each select="marc:subfield">
1597
          <xslo:if test="contains('avxyz', @code)" name="Match-heading:p Match-heading:s">
1926
          <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
1598
            <xslo:if test="position() &gt; 1">
1927
            <xslo:if test="position() &gt; 1">
1599
              <xslo:choose>
1928
              <xslo:choose>
1600
                <xslo:when test="contains('vxyz', @code)">
1929
                <xslo:when test="contains('vxyz', @code)">
Lines 1618-1624 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1618
                </xslo:otherwise>
1947
                </xslo:otherwise>
1619
              </xslo:choose>
1948
              </xslo:choose>
1620
            </xslo:if>
1949
            </xslo:if>
1621
            <xslo:value-of select="."/>
1950
            <xslo:call-template name="chopPunctuation">
1951
              <xslo:with-param name="chopString">
1952
                <xslo:value-of select="."/>
1953
              </xslo:with-param>
1954
            </xslo:call-template>
1622
          </xslo:if>
1955
          </xslo:if>
1623
        </xslo:for-each>
1956
        </xslo:for-each>
1624
      </xslo:variable>
1957
      </xslo:variable>
Lines 1626-1635 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1626
    </z:index>
1959
    </z:index>
1627
  </xslo:template>
1960
  </xslo:template>
1628
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='455']">
1961
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='455']">
1629
    <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
1962
    <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1630
      <xslo:variable name="raw_heading">
1963
      <xslo:variable name="raw_heading">
1631
        <xslo:for-each select="marc:subfield">
1964
        <xslo:for-each select="marc:subfield">
1632
          <xslo:if test="contains('avxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
1965
          <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
1633
            <xslo:if test="position() &gt; 1">
1966
            <xslo:if test="position() &gt; 1">
1634
              <xslo:choose>
1967
              <xslo:choose>
1635
                <xslo:when test="contains('vxyz', @code)">
1968
                <xslo:when test="contains('vxyz', @code)">
Lines 1653-1659 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1653
                </xslo:otherwise>
1986
                </xslo:otherwise>
1654
              </xslo:choose>
1987
              </xslo:choose>
1655
            </xslo:if>
1988
            </xslo:if>
1656
            <xslo:value-of select="."/>
1989
            <xslo:call-template name="chopPunctuation">
1990
              <xslo:with-param name="chopString">
1991
                <xslo:value-of select="."/>
1992
              </xslo:with-param>
1993
            </xslo:call-template>
1994
          </xslo:if>
1995
        </xslo:for-each>
1996
      </xslo:variable>
1997
      <xslo:value-of select="normalize-space($raw_heading)"/>
1998
    </z:index>
1999
  </xslo:template>
2000
  <xslo:template mode="index_match_heading" match="marc:datafield[@tag='555']">
2001
    <z:index name="Match:w Match:p">
2002
      <xslo:variable name="raw_heading">
2003
        <xslo:for-each select="marc:subfield">
2004
          <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p">
2005
            <xslo:if test="position() &gt; 1">
2006
              <xslo:choose>
2007
                <xslo:when test="contains('vxyz', @code)">
2008
                  <xslo:choose>
2009
                    <xslo:when test="@code = $general_subdivision_subfield">
2010
                      <xslo:text> generalsubdiv </xslo:text>
2011
                    </xslo:when>
2012
                    <xslo:when test="@code = $form_subdivision_subfield">
2013
                      <xslo:text> formsubdiv </xslo:text>
2014
                    </xslo:when>
2015
                    <xslo:when test="@code = $chronological_subdivision_subfield">
2016
                      <xslo:text> chronologicalsubdiv </xslo:text>
2017
                    </xslo:when>
2018
                    <xslo:when test="@code = $geographic_subdivision_subfield">
2019
                      <xslo:text> geographicsubdiv </xslo:text>
2020
                    </xslo:when>
2021
                  </xslo:choose>
2022
                </xslo:when>
2023
                <xslo:otherwise>
2024
                  <xslo:value-of select="substring(' ', 1, 1)"/>
2025
                </xslo:otherwise>
2026
              </xslo:choose>
2027
            </xslo:if>
2028
            <xslo:call-template name="chopPunctuation">
2029
              <xslo:with-param name="chopString">
2030
                <xslo:value-of select="."/>
2031
              </xslo:with-param>
2032
            </xslo:call-template>
1657
          </xslo:if>
2033
          </xslo:if>
1658
        </xslo:for-each>
2034
        </xslo:for-each>
1659
      </xslo:variable>
2035
      </xslo:variable>
Lines 1688-1694 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1688
                </xslo:otherwise>
2064
                </xslo:otherwise>
1689
              </xslo:choose>
2065
              </xslo:choose>
1690
            </xslo:if>
2066
            </xslo:if>
1691
            <xslo:value-of select="."/>
2067
            <xslo:call-template name="chopPunctuation">
2068
              <xslo:with-param name="chopString">
2069
                <xslo:value-of select="."/>
2070
              </xslo:with-param>
2071
            </xslo:call-template>
1692
          </xslo:if>
2072
          </xslo:if>
1693
        </xslo:for-each>
2073
        </xslo:for-each>
1694
      </xslo:variable>
2074
      </xslo:variable>
Lines 1723-1729 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1723
                </xslo:otherwise>
2103
                </xslo:otherwise>
1724
              </xslo:choose>
2104
              </xslo:choose>
1725
            </xslo:if>
2105
            </xslo:if>
1726
            <xslo:value-of select="."/>
2106
            <xslo:call-template name="chopPunctuation">
2107
              <xslo:with-param name="chopString">
2108
                <xslo:value-of select="."/>
2109
              </xslo:with-param>
2110
            </xslo:call-template>
1727
          </xslo:if>
2111
          </xslo:if>
1728
        </xslo:for-each>
2112
        </xslo:for-each>
1729
      </xslo:variable>
2113
      </xslo:variable>
Lines 1758-1764 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1758
                </xslo:otherwise>
2142
                </xslo:otherwise>
1759
              </xslo:choose>
2143
              </xslo:choose>
1760
            </xslo:if>
2144
            </xslo:if>
1761
            <xslo:value-of select="."/>
2145
            <xslo:call-template name="chopPunctuation">
2146
              <xslo:with-param name="chopString">
2147
                <xslo:value-of select="."/>
2148
              </xslo:with-param>
2149
            </xslo:call-template>
1762
          </xslo:if>
2150
          </xslo:if>
1763
        </xslo:for-each>
2151
        </xslo:for-each>
1764
      </xslo:variable>
2152
      </xslo:variable>
Lines 1793-1799 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1793
                </xslo:otherwise>
2181
                </xslo:otherwise>
1794
              </xslo:choose>
2182
              </xslo:choose>
1795
            </xslo:if>
2183
            </xslo:if>
1796
            <xslo:value-of select="."/>
2184
            <xslo:call-template name="chopPunctuation">
2185
              <xslo:with-param name="chopString">
2186
                <xslo:value-of select="."/>
2187
              </xslo:with-param>
2188
            </xslo:call-template>
1797
          </xslo:if>
2189
          </xslo:if>
1798
        </xslo:for-each>
2190
        </xslo:for-each>
1799
      </xslo:variable>
2191
      </xslo:variable>
Lines 1828-1834 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1828
                </xslo:otherwise>
2220
                </xslo:otherwise>
1829
              </xslo:choose>
2221
              </xslo:choose>
1830
            </xslo:if>
2222
            </xslo:if>
1831
            <xslo:value-of select="."/>
2223
            <xslo:call-template name="chopPunctuation">
2224
              <xslo:with-param name="chopString">
2225
                <xslo:value-of select="."/>
2226
              </xslo:with-param>
2227
            </xslo:call-template>
1832
          </xslo:if>
2228
          </xslo:if>
1833
        </xslo:for-each>
2229
        </xslo:for-each>
1834
      </xslo:variable>
2230
      </xslo:variable>
Lines 1863-1869 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1863
                </xslo:otherwise>
2259
                </xslo:otherwise>
1864
              </xslo:choose>
2260
              </xslo:choose>
1865
            </xslo:if>
2261
            </xslo:if>
1866
            <xslo:value-of select="."/>
2262
            <xslo:call-template name="chopPunctuation">
2263
              <xslo:with-param name="chopString">
2264
                <xslo:value-of select="."/>
2265
              </xslo:with-param>
2266
            </xslo:call-template>
1867
          </xslo:if>
2267
          </xslo:if>
1868
        </xslo:for-each>
2268
        </xslo:for-each>
1869
      </xslo:variable>
2269
      </xslo:variable>
Lines 1898-1904 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1898
                </xslo:otherwise>
2298
                </xslo:otherwise>
1899
              </xslo:choose>
2299
              </xslo:choose>
1900
            </xslo:if>
2300
            </xslo:if>
1901
            <xslo:value-of select="."/>
2301
            <xslo:call-template name="chopPunctuation">
2302
              <xslo:with-param name="chopString">
2303
                <xslo:value-of select="."/>
2304
              </xslo:with-param>
2305
            </xslo:call-template>
1902
          </xslo:if>
2306
          </xslo:if>
1903
        </xslo:for-each>
2307
        </xslo:for-each>
1904
      </xslo:variable>
2308
      </xslo:variable>
Lines 1933-1939 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1933
                </xslo:otherwise>
2337
                </xslo:otherwise>
1934
              </xslo:choose>
2338
              </xslo:choose>
1935
            </xslo:if>
2339
            </xslo:if>
1936
            <xslo:value-of select="."/>
2340
            <xslo:call-template name="chopPunctuation">
2341
              <xslo:with-param name="chopString">
2342
                <xslo:value-of select="."/>
2343
              </xslo:with-param>
2344
            </xslo:call-template>
1937
          </xslo:if>
2345
          </xslo:if>
1938
        </xslo:for-each>
2346
        </xslo:for-each>
1939
      </xslo:variable>
2347
      </xslo:variable>
Lines 1999-2002 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
1999
      <xslo:value-of select="."/>
2407
      <xslo:value-of select="."/>
2000
    </z:index>
2408
    </z:index>
2001
  </xslo:template>
2409
  </xslo:template>
2410
  <xslo:template name="chopPunctuation">
2411
    <xslo:param name="chopString"/>
2412
    <xslo:variable name="length" select="string-length($chopString)"/>
2413
    <xslo:choose>
2414
      <xslo:when test="$length=0"/>
2415
      <xslo:when test="contains('-,.:=;!%/', substring($chopString,$length,1))">
2416
        <xslo:call-template name="chopPunctuation">
2417
          <xslo:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
2418
        </xslo:call-template>
2419
      </xslo:when>
2420
      <xslo:when test="not($chopString)"/>
2421
      <xslo:otherwise>
2422
        <xslo:value-of select="$chopString"/>
2423
      </xslo:otherwise>
2424
    </xslo:choose>
2425
    <xslo:text/>
2426
  </xslo:template>
2002
</xslo:stylesheet>
2427
</xslo:stylesheet>
(-)a/etc/zebradb/marc_defs/marc21/authorities/koha-indexdefs-to-zebra.xsl (-1 / +20 lines)
Lines 67-72 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
67
                    <xslo:value-of select="."/>
67
                    <xslo:value-of select="."/>
68
                </z:index>
68
                </z:index>
69
            </xslo:template>
69
            </xslo:template>
70
            <xslo:template name="chopPunctuation">
71
            <xslo:param name="chopString"/>
72
                <xslo:variable name="length" select="string-length($chopString)"/>
73
                <xslo:choose>
74
                <xslo:when test="$length=0"/>
75
                <xslo:when test="contains('-,.:=;!%/', substring($chopString,$length,1))">
76
                    <xslo:call-template name="chopPunctuation">
77
                    <xslo:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
78
                    </xslo:call-template>
79
                </xslo:when>
80
                <xslo:when test="not($chopString)"/>
81
                <xslo:otherwise><xslo:value-of select="$chopString"/></xslo:otherwise>
82
                </xslo:choose>
83
                <xslo:text> </xslo:text>
84
            </xslo:template>
70
        </xslo:stylesheet>
85
        </xslo:stylesheet>
71
    </xsl:template>
86
    </xsl:template>
72
87
Lines 368-374 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
368
                                </xslo:otherwise>
383
                                </xslo:otherwise>
369
                            </xslo:choose>
384
                            </xslo:choose>
370
                        </xslo:if>
385
                        </xslo:if>
371
                        <xslo:value-of select="."/>
386
                        <xslo:call-template name="chopPunctuation">
387
                            <xslo:with-param name="chopString">
388
                                <xslo:value-of select="."/>
389
                            </xslo:with-param>
390
                        </xslo:call-template>
372
                    </xslo:if>
391
                    </xslo:if>
373
                </xslo:for-each>
392
                </xslo:for-each>
374
            </xslo:variable>
393
            </xslo:variable>
(-)a/etc/zebradb/marc_defs/unimarc/authorities/record.abs (-60 / +60 lines)
Lines 16-104 melm 942$a authtype Link Here
16
melm 152$b authtype:w,authtype:p
16
melm 152$b authtype:w,authtype:p
17
17
18
# Personal Name
18
# Personal Name
19
melm 200$a Personal-name-heading:w,Personal-name-heading:p,Personal-name-heading:s,Personal-name:w,Personal-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
19
melm 200$a Personal-name-heading:w,Personal-name-heading:p,Personal-name-heading:s,Personal-name:w,Personal-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
20
melm 200 Personal-name:w,Personal-name:p,Heading:w,Heading:p
20
melm 200 Personal-name:w,Personal-name:p,Heading:w,Heading:p,Match:w,Match:p
21
melm 400 Personal-name-see:w,Personal-name-see:p,See:w,See:p
21
melm 400 Personal-name-see:w,Personal-name-see:p,See:w,See:p,Match:w,Match:p
22
melm 500 Personal-name-see-also:w,Personal-name-see-also:p,See-also:w,See-also:p
22
melm 500 Personal-name-see-also:w,Personal-name-see-also:p,See-also:w,See-also:p,Match:w,Match:p
23
melm 700$a Personal-name-parallel:w,Personal-name-parallel:p,Parallel:w,Parallel:p
23
melm 700$a Personal-name-parallel:w,Personal-name-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
24
24
25
# Corporate Name
25
# Corporate Name
26
melm 210$a Corporate-name-heading:w,Corporate-name-heading:p,Corporate-name-heading:s,Corporate-name:w,Corporate-name:p,Conference-name-heading:w,Conference-name-heading:p,Conference-name-heading:s,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
26
melm 210$a Corporate-name-heading:w,Corporate-name-heading:p,Corporate-name-heading:s,Corporate-name:w,Corporate-name:p,Conference-name-heading:w,Conference-name-heading:p,Conference-name-heading:s,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
27
melm 210 Corporate-name:w,Corporate-name:p,Conference-name:w,Conference-name:p,Heading:w,Heading:p
27
melm 210 Corporate-name:w,Corporate-name:p,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Match:w,Match:p
28
melm 410 Corporate-name-see:w,Corporate-name-see:p,Conference-name-see:w,Conference-name-see:p,See:w,See:p
28
melm 410 Corporate-name-see:w,Corporate-name-see:p,Conference-name-see:w,Conference-name-see:p,See:w,See:p,Match:w,Match:p
29
melm 510 Corporate-name-see-also:w,Corporate-name-see-also:p,Conference-name-see-also:w,Conference-name-see-also:p,See-also:w,See-also:p
29
melm 510 Corporate-name-see-also:w,Corporate-name-see-also:p,Conference-name-see-also:w,Conference-name-see-also:p,See-also:w,See-also:p,Match:w,Match:p
30
melm 710 Corporate-name-parallel:w,Corporate-name-parallel:p,Parallel:w,Parallel:p
30
melm 710 Corporate-name-parallel:w,Corporate-name-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
31
31
32
32
33
# Geographic & Geographic Name
33
# Geographic & Geographic Name
34
melm 215$a Name-geographic-heading:w,Name-geographic-heading:w,Name-geographic-heading:s,Name-geographic:w,Name-geographic:p,Term-geographic-heading:w,Term-geographic-heading:p,Term-geographic-heading:s,Term-geographic:w,Term-geographic:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
34
melm 215$a Name-geographic-heading:w,Name-geographic-heading:w,Name-geographic-heading:s,Name-geographic:w,Name-geographic:p,Term-geographic-heading:w,Term-geographic-heading:p,Term-geographic-heading:s,Term-geographic:w,Term-geographic:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
35
melm 215 Name-geographic-heading:w,Name-geographic-heading:w,Name-geographic-heading:s,Name-geographic:w,Name-geographic:p,Term-geographic:w,Term-geographic:p,Term-geographic:s,Heading:w,Heading:p,Heading:s
35
melm 215 Name-geographic-heading:w,Name-geographic-heading:w,Name-geographic-heading:s,Name-geographic:w,Name-geographic:p,Term-geographic:w,Term-geographic:p,Term-geographic:s,Heading:w,Heading:p,Heading:s,Match:w,Match:p
36
melm 415 Name-geographic-see:w,Name-geographic-see:p,Term-geographic-see:w,Term-geographic-see:p,Term-geographic-see:s,See:w,See:p,See:s
36
melm 415 Name-geographic-see:w,Name-geographic-see:p,Term-geographic-see:w,Term-geographic-see:p,Term-geographic-see:s,See:w,See:p,See:s,Match:w,Match:p
37
melm 515 Name-geographic-see-also:w,Name-geographic-see-also:p,Term-geographic-see-also:w,Term-geographic-see-also:p,Term-geographic-see-also:s,See-also:w,See-also:p,See-also:s
37
melm 515 Name-geographic-see-also:w,Name-geographic-see-also:p,Term-geographic-see-also:w,Term-geographic-see-also:p,Term-geographic-see-also:s,See-also:w,See-also:p,See-also:s,Match:w,Match:p
38
melm 715 Name-geographic-parallel:w,Name-geographic-parallel:p,Term-geographic-parallel:w,Term-geographic-parallel:p,Term-geographic-parallel:s,Parallel:w,Parallel:p,Parallel:s
38
melm 715 Name-geographic-parallel:w,Name-geographic-parallel:p,Term-geographic-parallel:w,Term-geographic-parallel:p,Term-geographic-parallel:s,Parallel:w,Parallel:p,Parallel:s,Match:w,Match:p
39
39
40
# Trademark
40
# Trademark
41
melm 216$a Trademark-heading:w,Trademark-heading:p,Trademark-heading:s,Trademark:w,Trademark:p,Conference-name-heading:w,Conference-name-heading:p,Conference-name-heading:s,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
41
melm 216$a Trademark-heading:w,Trademark-heading:p,Trademark-heading:s,Trademark:w,Trademark:p,Conference-name-heading:w,Conference-name-heading:p,Conference-name-heading:s,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
42
melm 216 Trademark:w,Trademark:p,Conference-name:w,Conference-name:p,Heading:w,Heading:p
42
melm 216 Trademark:w,Trademark:p,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Match:w,Match:p
43
melm 416 Trademark-see:w,Trademark-see:p,Conference-name-see:w,Conference-name-see:p,See:w,See:p
43
melm 416 Trademark-see:w,Trademark-see:p,Conference-name-see:w,Conference-name-see:p,See:w,See:p,Match:w,Match:p
44
melm 516 Trademark-see-also:w,Trademark-see-also:p,Conference-name-see-also:w,Conference-name-see-also:p,See-also:w,See-also:p
44
melm 516 Trademark-see-also:w,Trademark-see-also:p,Conference-name-see-also:w,Conference-name-see-also:p,See-also:w,See-also:p,Match:w,Match:p
45
melm 716 Trademark-parallel:w,Trademark-parallel:p,Parallel:w,Parallel:p
45
melm 716 Trademark-parallel:w,Trademark-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
46
46
47
# Family Name
47
# Family Name
48
melm 220$a Name-heading:w,Name-heading:p,Name-heading:s,Name:w,Name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
48
melm 220$a Name-heading:w,Name-heading:p,Name-heading:s,Name:w,Name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
49
melm 220 Name:w,Name:p,Name:s,Heading:w,Heading:p,Heading:s
49
melm 220 Name:w,Name:p,Name:s,Heading:w,Heading:p,Heading:s,Match:w,Match:p
50
melm 420 Name-see:w,Name-see:p,Name-see:s,See:w,See:p,See:s
50
melm 420 Name-see:w,Name-see:p,Name-see:s,See:w,See:p,See:s,Match:w,Match:p
51
melm 520 Name-see-also:w,Name-see-also:p,Name-see-also:s,See-also:w,See-also:p,See-also:s
51
melm 520 Name-see-also:w,Name-see-also:p,Name-see-also:s,See-also:w,See-also:p,See-also:s,Match:w,Match:p
52
melm 720 Name-parallel:w,Name-parallel:p,Name-parallel:s,Parallel:w,Parallel:p,Parallel:s
52
melm 720 Name-parallel:w,Name-parallel:p,Name-parallel:s,Parallel:w,Parallel:p,Parallel:s,Match:w,Match:p
53
53
54
# Uniform Title
54
# Uniform Title
55
melm 230$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
55
melm 230$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
56
melm 230 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p
56
melm 230 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Match:w,Match:p
57
melm 430 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p
57
melm 430 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p,Match:w,Match:p
58
melm 530 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p
58
melm 530 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p,Match:w,Match:p
59
melm 730$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p
59
melm 730$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
60
60
61
# Second area for uniform titles in UNIMARC?
61
# Second area for uniform titles in UNIMARC?
62
melm 235$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
62
melm 235$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
63
melm 235 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p
63
melm 235 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Match:w,Match:p
64
melm 435 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p
64
melm 435 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p,Match:w,Match:p
65
melm 535 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p
65
melm 535 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p,Match:w,Match:p
66
melm 735$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p
66
melm 735$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
67
67
68
# Uniform Title
68
# Uniform Title
69
melm 240$a Name-Title-heading:w,Name-Title-heading:p,Name-Title-heading:s,Name-Title:w,Name-Title:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
69
melm 240$a Name-Title-heading:w,Name-Title-heading:p,Name-Title-heading:s,Name-Title:w,Name-Title:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
70
melm 240 Name-Title:w,Name-Title:p,Heading:w,Heading:p
70
melm 240 Name-Title:w,Name-Title:p,Heading:w,Heading:p,Match:w,Match:p
71
melm 440 Name-Title-see:w,Name-Title-see:p,See:w,See:p
71
melm 440 Name-Title-see:w,Name-Title-see:p,See:w,See:p,Match:w,Match:p
72
melm 540 Name-Title-see-also:w,Name-Title-see-also:p,See-also:w,See-also:p
72
melm 540 Name-Title-see-also:w,Name-Title-see-also:p,See-also:w,See-also:p,Match:w,Match:p
73
melm 740$a Name-Title-parallel:w,Name-Title-parallel:p,Parallel:w,Parallel:p
73
melm 740$a Name-Title-parallel:w,Name-Title-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
74
74
75
# Second area for uniform titles in UNIMARC?
75
# Second area for uniform titles in UNIMARC?
76
melm 245$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
76
melm 245$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
77
melm 245 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p
77
melm 245 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Match:w,Match:p
78
melm 445 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p
78
melm 445 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p,Match:w,Match:p
79
melm 545 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p
79
melm 545 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p,Match:w,Match:p
80
melm 745$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p
80
melm 745$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
81
81
82
# Topical Term
82
# Topical Term
83
melm 250$a Subject-heading:w,Subject-heading:p,Subject-heading:s,Subject:w,Subject:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
83
melm 250$a Subject-heading:w,Subject-heading:p,Subject-heading:s,Subject:w,Subject:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
84
melm 250 Subject:w,Subject:p,Heading:w,Heading:p,Subject-heading:w,Subject-heading:p,Subject-heading:s
84
melm 250 Subject:w,Subject:p,Heading:w,Heading:p,Subject-heading:w,Subject-heading:p,Subject-heading:s,Match:w,Match:p
85
melm 450 Subject-see:w,Subject-see:p,See:w,See:p
85
melm 450 Subject-see:w,Subject-see:p,See:w,See:p,Match:w,Match:p
86
melm 550 Subject-see-also:w,Subject-see-also:p,See-also:w,See-also:p
86
melm 550 Subject-see-also:w,Subject-see-also:p,See-also:w,See-also:p,Match:w,Match:p
87
melm 750$a Subject-parallel:w,Subject-parallel:p,Parallel:w,Parallel:p
87
melm 750$a Subject-parallel:w,Subject-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
88
88
89
# Place Access
89
# Place Access
90
melm 260$a Place-heading:w,Place-heading:p,Place-heading:s,Place:w,Place:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
90
melm 260$a Place-heading:w,Place-heading:p,Place-heading:s,Place:w,Place:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
91
melm 260 Place:w,Place:p,Heading:w,Heading:p,Place-heading:w,Place-heading:p,Place-heading:s
91
melm 260 Place:w,Place:p,Heading:w,Heading:p,Place-heading:w,Place-heading:p,Place-heading:s,Match:w,Match:p
92
melm 460 Place-see:w,Place-see:p,See:w,See:p
92
melm 460 Place-see:w,Place-see:p,See:w,See:p,Match:w,Match:p
93
melm 560 Place-see-also:w,Place-see-also:p,See-also:w,See-also:p
93
melm 560 Place-see-also:w,Place-see-also:p,See-also:w,See-also:p,Match:w,Match:p
94
melm 760$a Place-parallel:w,Place-parallel:p,Parallel:w,Parallel:p
94
melm 760$a Place-parallel:w,Place-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
95
95
96
# Form Genre
96
# Form Genre
97
melm 280$a Form-heading:w,Form-heading:p,Form-heading:s,Form:w,Form:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
97
melm 280$a Form-heading:w,Form-heading:p,Form-heading:s,Form:w,Form:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
98
melm 280 Form:w,Form:p,Heading:w,Heading:p,Form-heading:w,Form-heading:p,Form-heading:s
98
melm 280 Form:w,Form:p,Heading:w,Heading:p,Form-heading:w,Form-heading:p,Form-heading:s,Match:w,Match:p
99
melm 480 Form-see:w,Form-see:p,See:w,See:p
99
melm 480 Form-see:w,Form-see:p,See:w,See:p,Match:w,Match:p
100
melm 580 Form-see-also:w,Form-see-also:p,See-also:w,See-also:p
100
melm 580 Form-see-also:w,Form-see-also:p,See-also:w,See-also:p,Match:w,Match:p
101
melm 780$a Form-parallel:w,Form-parallel:p,Parallel:w,Parallel:p
101
melm 780$a Form-parallel:w,Form-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
102
102
103
103
104
# NOTE: subdivisions management missing from Koha
104
# NOTE: subdivisions management missing from Koha
(-)a/installer/data/mysql/atomicupdate/bug_7284_authority_linking_pt1 (+21 lines)
Line 0 Link Here
1
#! /usr/bin/perl
2
use strict;
3
use warnings;
4
use C4::Context;
5
my $dbh = C4::Context->dbh;
6
$dbh->do(
7
"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerModule','Default','Chooses which linker module to use (see documentation).','Default|FirstMatchLastMatch','Choice');"
8
);
9
$dbh->do(
10
"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerOptions','','A pipe-separated list of options for the linker.','','free');"
11
);
12
$dbh->do(
13
"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerRelink',1,'If ON the authority linker will relink headings that have previously been linked every time it runs.',NULL,'YesNo');"
14
);
15
$dbh->do(
16
"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerKeepStale',0,'If ON the authority linker will keep existing authority links for headings where it is unable to find a match.',NULL,'YesNo');"
17
);
18
$dbh->do(
19
"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('AutoCreateAuthorities',0,'Automatically create authorities that do not exist when cataloging records.',NULL,'YesNo');"
20
);
21
print "Upgrade done (Configured bug 7284, improved authority matching)\n";
(-)a/installer/data/mysql/atomicupdate/bug_7284_authority_linking_pt2 (+9 lines)
Line 0 Link Here
1
#! /usr/bin/perl
2
use strict;
3
use warnings;
4
use C4::Context;
5
my $dbh = C4::Context->dbh;
6
$dbh->do(
7
"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('CatalogModuleRelink',0,'If OFF the linker will never replace the authids that are set in the cataloging module.',NULL,'YesNo');"
8
);
9
print "Upgrade done (Configured bug 7284, added the )\n";
(-)a/installer/data/mysql/sysprefs.sql (+6 lines)
Lines 336-338 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
336
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('BorrowerRenewalPeriodBase', 'now', 'Set whether the borrower renewal date should be counted from the dateexpiry or from the current date ','dateexpiry|now','Choice');
336
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('BorrowerRenewalPeriodBase', 'now', 'Set whether the borrower renewal date should be counted from the dateexpiry or from the current date ','dateexpiry|now','Choice');
337
INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES ('AllowItemsOnHoldCheckout',0,'Do not generate RESERVE_WAITING and RESERVED warning when checking out items reserved to someone else. This allows self checkouts for those items.','','YesNo');
337
INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES ('AllowItemsOnHoldCheckout',0,'Do not generate RESERVE_WAITING and RESERVED warning when checking out items reserved to someone else. This allows self checkouts for those items.','','YesNo');
338
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacExportOptions','bibtex|dc|marcxml|marc8|utf8|marcstd|mods|ris','Define export options available on OPAC detail page.','','free');
338
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacExportOptions','bibtex|dc|marcxml|marc8|utf8|marcstd|mods|ris','Define export options available on OPAC detail page.','','free');
339
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('AutoCreateAuthorities',0,'Automatically create authorities that do not exist when cataloging records.',NULL,'YesNo');
340
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerModule','Default','Chooses which linker module to use (see documentation).','Default|FirstMatch|LastMatch','Choice');
341
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerOptions','','A pipe-separated list of options for the linker.','','free');
342
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerRelink',1,'If ON the authority linker will relink headings that have previously been linked every time it runs.',NULL,'YesNo');
343
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerKeepStale',0,'If ON the authority linker will keep existing authority links for headings where it is unable to find a match.',NULL,'YesNo');
344
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('CatalogModuleRelink',0,'If OFF the linker will never replace the authids that are set in the cataloging module.',NULL,'YesNo');
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/auth-finder-search.inc (-1 / +13 lines)
Lines 33-39 Link Here
33
                </li>
33
                </li>
34
                <li>
34
                <li>
35
                    <label for="marclist">Anywhere</label>
35
                    <label for="marclist">Anywhere</label>
36
                    <input type="hidden" name="marclist" value="" />
36
                    <input type="hidden" name="marclist" value="any" />
37
                    <input type="hidden" name="and_or" value="and" />
37
                    <input type="hidden" name="and_or" value="and" />
38
                    <input type="hidden" name="excluding" value="" />
38
                    <input type="hidden" name="excluding" value="" />
39
                    <select name="operator" id="marclist">
39
                    <select name="operator" id="marclist">
Lines 43-48 Link Here
43
                    </select>
43
                    </select>
44
                    <input type="text" name="value_any" value="[% value_any |html %]" />
44
                    <input type="text" name="value_any" value="[% value_any |html %]" />
45
                </li>
45
                </li>
46
                <li>
47
                    <label for="marclist">Heading match</label>
48
                    <input type="hidden" name="marclist" value="match" />
49
                    <input type="hidden" name="and_or" value="and" />
50
                    <input type="hidden" name="excluding" value="" />
51
                    <select name="operator" id="marclist">
52
                        <option value="contains">contains</option>
53
                        <option value="start">starts with</option>
54
                        <option value="is">is exactly</option>
55
                    </select>
56
                    <input type="text" name="value_match" value="[% value_match |html %]" />
57
                </li>
46
		<li>
58
		<li>
47
		<label for="orderby">Sort by </label>
59
		<label for="orderby">Sort by </label>
48
		<select name="orderby" id="orderby">
60
		<select name="orderby" id="orderby">
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/authorities.pref (-28 / +73 lines)
Lines 1-29 Link Here
1
Authorities:
1
Authorities:
2
    -
2
    General:
3
        - When editing records,
3
        -
4
        - pref: BiblioAddsAuthorities
4
            - When editing records,
5
          default: no
5
            - pref: BiblioAddsAuthorities
6
          choices:
6
              default: no
7
              yes: allow
7
              choices:
8
              no: "don't allow"
8
                  yes: allow
9
        - them to automatically create new authority records if needed, rather than having to reference existing authorities.
9
                  no: "don't allow"
10
    -
10
            - them to automatically create new authority records if needed, rather than having to reference existing authorities.
11
        - pref: dontmerge
11
        -
12
          default: yes
12
            - When editing records,
13
          choices:
13
            - pref: AutoCreateAuthorities
14
              yes: "Don't"
14
              default: yes
15
              no: Do
15
              choices:
16
        - automatically update attached biblios when changing an authority record. If this is off, please ask your administrator to enable the merge_authority.pl cronjob.
16
                  yes: generate
17
    -
17
                  no: "do not generate"
18
        - Use the following text for the contents of MARC authority control field 008 position 06-39 (fixed length data elements). Do NOT include the date (position 00-05).
18
            - authority records that are missing (BiblioAddsAuthorities must be set to "allow" for this to have any effect).
19
        - pref: MARCAuthorityControlField008
19
        -
20
          default: "|| aca||aabn           | a|a     d"
20
            - pref: dontmerge
21
          type: textarea
21
              default: yes
22
          class: code
22
              choices:
23
    -
23
                  yes: "Don't"
24
        - pref: UseAuthoritiesForTracings
24
                  no: Do
25
          default: yes
25
            - automatically update attached biblios when changing an authority record. If this is off, please ask your administrator to enable the merge_authority.pl cronjob.
26
          choices:
26
        -
27
              yes: Use
27
            - Use the following text for the contents of MARC authority control field 008 position 06-39 (fixed length data elements). Do NOT include the date (position 00-05).
28
              no: "Don't use"
28
            - pref: MARCAuthorityControlField008
29
        - authority record numbers instead of text strings for searches from subject tracings.
29
              default: "|| aca||aabn           | a|a     d"
30
              type: textarea
31
              class: code
32
        -
33
            - pref: UseAuthoritiesForTracings
34
              default: yes
35
              choices:
36
                  yes: Use
37
                  no: "Don't use"
38
            - authority record numbers instead of text strings for searches from subject tracings.
39
    Linker:
40
        -
41
            - Use the
42
            - pref: LinkerModule
43
              default: Default
44
              choices:
45
                  Default: Default
46
                  FirstMatch: "First Match"
47
                  LastMatch: "Last Match"
48
            - linker module for matching headings to authority records.
49
        -
50
            - Set the following options for the authority linker
51
            - pref: LinkerOptions
52
              class: multi
53
            - (separate options with |)
54
        -
55
            - pref: LinkerRelink
56
              default: yes
57
              choices:
58
                  yes: Do
59
                  no: "Do not"
60
            - relink headings that have previously been linked to authority records.
61
        -
62
            - pref: LinkerKeepStale
63
              default: no
64
              choices:
65
                  yes: Do
66
                  no: "Do not"
67
            - keep existing links to authority records for headings where the linker is unable to find a match.
68
        -
69
            - pref: CatalogModuleRelink
70
              default: no
71
              choices:
72
                  yes: Do
73
                  no: "Do not"
74
            - automatically relink headings that have previously been linked when saving records in the cataloging module.
(-)a/misc/link_bibs_to_authorities.pl (-52 / +215 lines)
Lines 2-8 Link Here
2
2
3
use strict;
3
use strict;
4
use warnings;
4
use warnings;
5
5
BEGIN {
6
BEGIN {
7
6
    # find Koha's Perl modules
8
    # find Koha's Perl modules
7
    # test carefully before changing this
9
    # test carefully before changing this
8
    use FindBin;
10
    use FindBin;
Lines 12-97 BEGIN { Link Here
12
use C4::Context;
14
use C4::Context;
13
use C4::Biblio;
15
use C4::Biblio;
14
use Getopt::Long;
16
use Getopt::Long;
17
use Pod::Usage;
18
use Data::Dumper;
19
use Time::HiRes qw/time/;
20
use POSIX qw/strftime ceil/;
21
22
sub usage {
23
    pod2usage( -verbose => 2 );
24
    exit;
25
}
15
26
16
$| = 1;
27
$| = 1;
17
28
18
# command-line parameters
29
# command-line parameters
19
my $verbose   = 0;
30
my $verbose     = 0;
20
my $test_only = 0;
31
my $link_report = 0;
21
my $want_help = 0;
32
my $test_only   = 0;
33
my $want_help   = 0;
34
my $auth_limit;
35
my $bib_limit;
36
my $commit = 100;
22
37
23
my $result = GetOptions(
38
my $result = GetOptions(
24
    'verbose'       => \$verbose,
39
    'v|verbose'      => \$verbose,
25
    'test'          => \$test_only,
40
    't|test'         => \$test_only,
26
    'h|help'        => \$want_help
41
    'l|link-report'  => \$link_report,
42
    'a|auth-limit=s' => \$auth_limit,
43
    'b|bib-limit=s'  => \$bib_limit,
44
    'c|commit=i'     => \$commit,
45
    'h|help'         => \$want_help
27
);
46
);
28
47
29
if (not $result or $want_help) {
48
binmode( STDOUT, ":utf8" );
30
    print_usage();
49
31
    exit 0;
50
if ( not $result or $want_help ) {
51
    usage();
52
}
53
54
my $linker_module =
55
  "C4::Linker::" . ( C4::Context->preference("LinkerModule") || 'Default' );
56
eval { eval "require $linker_module"; };
57
if ($@) {
58
    $linker_module = 'C4::Linker::Default';
59
    eval "require $linker_module";
32
}
60
}
61
if ($@) {
62
    die "Unable to load linker module. Aborting.";
63
}
64
65
my $linker = $linker_module->new(
66
    {
67
        'auth_limit' => $auth_limit,
68
        'options'    => C4::Context->preference("LinkerOptions")
69
    }
70
);
33
71
34
my $num_bibs_processed = 0;
72
my $num_bibs_processed = 0;
35
my $num_bibs_modified = 0;
73
my $num_bibs_modified  = 0;
36
my $num_bad_bibs = 0;
74
my $num_bad_bibs       = 0;
75
my %unlinked_headings;
76
my %linked_headings;
77
my %fuzzy_headings;
37
my $dbh = C4::Context->dbh;
78
my $dbh = C4::Context->dbh;
38
$dbh->{AutoCommit} = 0;
79
$dbh->{AutoCommit} = 0;
39
process_bibs();
80
process_bibs( $linker, $bib_limit, $auth_limit, $commit );
40
$dbh->commit();
81
$dbh->commit();
41
82
42
exit 0;
83
exit 0;
43
84
44
sub process_bibs {
85
sub process_bibs {
45
    my $sql = "SELECT biblionumber FROM biblio ORDER BY biblionumber ASC";
86
    my ( $linker, $bib_limit, $auth_limit, $commit ) = @_;
87
    my $bib_where = '';
88
    my $starttime = time();
89
    if ($bib_limit) {
90
        $bib_where = "WHERE $bib_limit";
91
    }
92
    my $sql =
93
      "SELECT biblionumber FROM biblio $bib_where ORDER BY biblionumber ASC";
46
    my $sth = $dbh->prepare($sql);
94
    my $sth = $dbh->prepare($sql);
47
    $sth->execute();
95
    $sth->execute();
48
    while (my ($biblionumber) = $sth->fetchrow_array()) {
96
    while ( my ($biblionumber) = $sth->fetchrow_array() ) {
49
        $num_bibs_processed++;
97
        $num_bibs_processed++;
50
        process_bib($biblionumber);
98
        process_bib( $linker, $biblionumber );
51
99
52
        if (not $test_only and ($num_bibs_processed % 100) == 0) {
100
        if ( not $test_only and ( $num_bibs_processed % $commit ) == 0 ) {
53
            print_progress_and_commit($num_bibs_processed);
101
            print_progress_and_commit($num_bibs_processed);
54
        }
102
        }
55
    }
103
    }
56
104
57
    if (not $test_only) {
105
    if ( not $test_only ) {
58
        $dbh->commit;
106
        $dbh->commit;
59
    }
107
    }
60
108
61
    print <<_SUMMARY_;
109
    my $headings_linked   = 0;
110
    my $headings_unlinked = 0;
111
    my $headings_fuzzy    = 0;
112
    for ( values %linked_headings )   { $headings_linked   += $_; }
113
    for ( values %unlinked_headings ) { $headings_unlinked += $_; }
114
    for ( values %fuzzy_headings )    { $headings_fuzzy    += $_; }
115
116
    my $endtime = time();
117
    my $totaltime = ceil (($endtime - $starttime) * 1000);
118
    $starttime = strftime('%D %T', localtime($starttime));
119
    $endtime = strftime('%D %T', localtime($endtime));
120
121
    my $summary = <<_SUMMARY_;
62
122
63
Bib authority heading linking report
123
Bib authority heading linking report
64
------------------------------------
124
=======================================================
65
Number of bibs checked:       $num_bibs_processed
125
Linker module:                          $linker_module
66
Number of bibs modified:      $num_bibs_modified
126
Run started at:                         $starttime
67
Number of bibs with errors:   $num_bad_bibs
127
Run ended at:                           $endtime
128
Total run time:                         $totaltime ms
129
Number of bibs checked:                 $num_bibs_processed
130
Number of bibs modified:                $num_bibs_modified
131
Number of bibs with errors:             $num_bad_bibs
132
Number of headings linked:              $headings_linked
133
Number of headings unlinked:            $headings_unlinked
134
Number of headings fuzzily linked:      $headings_fuzzy
68
_SUMMARY_
135
_SUMMARY_
136
    $summary .= "\n****  Ran in test mode only  ****\n" if $test_only;
137
    print $summary;
138
139
    if ($link_report) {
140
        my @keys;
141
        print <<_LINKED_HEADER_;
142
143
Linked headings (from most frequent to least):
144
-------------------------------------------------------
145
146
_LINKED_HEADER_
147
148
        @keys = sort {
149
            $linked_headings{$b} <=> $linked_headings{$a} or "\L$a" cmp "\L$b"
150
        } keys %linked_headings;
151
        foreach my $key (@keys) {
152
            print "$key:\t" . $linked_headings{$key} . " occurrences\n";
153
        }
154
155
        print <<_UNLINKED_HEADER_;
156
157
Unlinked headings (from most frequent to least):
158
-------------------------------------------------------
159
160
_UNLINKED_HEADER_
161
162
        @keys = sort {
163
            $unlinked_headings{$b} <=> $unlinked_headings{$a}
164
              or "\L$a" cmp "\L$b"
165
        } keys %unlinked_headings;
166
        foreach my $key (@keys) {
167
            print "$key:\t" . $unlinked_headings{$key} . " occurrences\n";
168
        }
169
170
        print <<_FUZZY_HEADER_;
171
172
Fuzzily-matched headings (from most frequent to least):
173
-------------------------------------------------------
174
175
_FUZZY_HEADER_
176
177
        @keys = sort {
178
            $fuzzy_headings{$b} <=> $fuzzy_headings{$a} or "\L$a" cmp "\L$b"
179
        } keys %fuzzy_headings;
180
        foreach my $key (@keys) {
181
            print "$key:\t" . $fuzzy_headings{$key} . " occurrences\n";
182
        }
183
        print $summary;
184
    }
69
}
185
}
70
186
71
sub process_bib {
187
sub process_bib {
188
    my $linker       = shift;
72
    my $biblionumber = shift;
189
    my $biblionumber = shift;
73
190
74
    my $bib = GetMarcBiblio($biblionumber);
191
    my $bib = GetMarcBiblio($biblionumber);
75
    unless (defined $bib) {
192
    unless ( defined $bib ) {
76
        print "\nCould not retrieve bib $biblionumber from the database - record is corrupt.\n";
193
        print
194
"\nCould not retrieve bib $biblionumber from the database - record is corrupt.\n";
77
        $num_bad_bibs++;
195
        $num_bad_bibs++;
78
        return;
196
        return;
79
    }
197
    }
80
198
81
    my $headings_changed = LinkBibHeadingsToAuthorities($bib);
199
    my ( $headings_changed, $results ) =
200
      LinkBibHeadingsToAuthorities( $linker, $bib,
201
        GetFrameworkCode($biblionumber) );
202
    foreach my $key ( keys %{ $results->{'unlinked'} } ) {
203
        $unlinked_headings{$key} += $results->{'unlinked'}->{$key};
204
    }
205
    foreach my $key ( keys %{ $results->{'linked'} } ) {
206
        $linked_headings{$key} += $results->{'linked'}->{$key};
207
    }
208
    foreach my $key ( keys %{ $results->{'fuzzy'} } ) {
209
        $fuzzy_headings{$key} += $results->{'fuzzy'}->{$key};
210
    }
82
211
83
    if ($headings_changed) {   
212
    if ($headings_changed) {
84
        if ($verbose) {
213
        if ($verbose) {
85
            my $title = substr($bib->title, 0, 20);
214
            my $title = substr( $bib->title, 0, 20 );
86
            print "Bib $biblionumber ($title): $headings_changed headings changed\n";
215
            print
216
"Bib $biblionumber ($title): $headings_changed headings changed\n";
87
        }
217
        }
88
        if (not $test_only) {
218
        if ( not $test_only ) {
89
            # delete any item tags
219
            ModBiblio( $bib, $biblionumber, GetFrameworkCode($biblionumber) );
90
            my ($itemtag, $itemsubfield) = GetMarcFromKohaField("items.itemnumber", '');
91
            foreach my $field ($bib->field($itemtag)) {
92
                $bib->delete_field($field);
93
            }
94
            ModBiblio($bib, $biblionumber, GetFrameworkCode($biblionumber));
95
            $num_bibs_modified++;
220
            $num_bibs_modified++;
96
        }
221
        }
97
    }
222
    }
Lines 103-122 sub print_progress_and_commit { Link Here
103
    print "... processed $recs records\n";
228
    print "... processed $recs records\n";
104
}
229
}
105
230
106
sub print_usage {
231
=head1 NAME
107
    print <<_USAGE_;
232
108
$0: link headings in bib records to authorities.
233
link_bibs_to_authorities.pl
109
234
110
This batch job checks each bib record in the Koha
235
=head1 SYNOPSIS
111
database and attempts to link each of its headings
236
112
to the matching authority record.
237
  link_bibs_to_authorities.pl
113
238
  link_bibs_to_authorities.pl -v
114
Parameters:
239
  link_bibs_to_authorities.pl -l
115
    --verbose               print the number of headings changed
240
  link_bibs_to_authorities.pl --commit=1000
116
                            for each bib
241
  link_bibs_to_authorities.pl --auth-limit=STRING
117
    --test                  only test the authority linking
242
  link_bibs_to_authorities.pl --bib-limit=STRING
118
                            and report the results; do not
243
119
                            change the bib records.
244
=head1 DESCRIPTION
120
    --help or -h            show this message.
245
121
_USAGE_
246
This batch job checks each bib record in the Koha database and attempts to link
122
}
247
each of its headings to the matching authority record.
248
249
=over 8
250
251
=item B<--help>
252
253
Prints this help
254
255
=item B<-v|--verbose>
256
257
Provide verbose log information (print the number of headings changed for each
258
bib record).
259
260
=item B<-l|--link-report>
261
262
Provide a report of all the headings that were processed: which were matched,
263
which were not, etc.
264
265
=item B<--auth-limit=S>
266
267
Only process those headings which match an authority record that matches the
268
user-specified WHERE clause.
269
270
=item B<--bib-limit=S>
271
272
Only process those bib records that match the user-specified WHERE clause.
273
274
=item B<--commit=N>
275
276
Commit the results to the database after every N records are processed.
277
278
=item B<--test>
279
280
Only test the authority linking and report the results; do not change the bib
281
records.
282
283
=back
284
285
=cut
(-)a/t/Heading_MARC21.t (-2 / +6 lines)
Lines 6-14 Link Here
6
use strict;
6
use strict;
7
use warnings;
7
use warnings;
8
8
9
use Test::More tests => 1;
9
use Test::More tests => 3;
10
10
11
BEGIN {
11
BEGIN {
12
        use_ok('C4::External::Amazon');
12
        use_ok('C4::Heading');
13
}
13
}
14
14
15
my $field = MARC::Field->new( '650', ' ', '0', a => 'Uncles', x => 'Fiction' );
16
my $heading = C4::Heading->new_from_bib_field($field);
17
is($heading->display_form(), 'Uncles--Fiction', 'Display form generation');
18
is($heading->search_form(), 'Uncles generalsubdiv Fiction', 'Search form generation');
(-)a/t/db_dependent/Linker_FirstMatch.t (+46 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
#
3
# This Koha test module is a stub!
4
# Add more tests here!!!
5
6
use strict;
7
use warnings;
8
use Test::More tests => 3;
9
use C4::Context;
10
use C4::Heading;
11
use MARC::Record;
12
use MARC::Field;
13
use C4::Linker::FirstMatch;
14
15
16
BEGIN {
17
        use_ok('C4::Linker');
18
}
19
my $dbh = C4::Context->dbh;
20
21
my $query = "SELECT authid, marc FROM auth_header LIMIT 1;";
22
my $sth = $dbh->prepare($query);
23
$sth->execute();
24
my ($authid, $marc) = $sth->fetchrow_array();
25
SKIP: {
26
    skip "No authorities", 2 unless defined $authid;
27
    my $linker = C4::Linker::FirstMatch->new();
28
    my $auth = MARC::Record->new_from_usmarc($marc);
29
    my $fieldmatch;
30
    if (C4::Context->preference('MARCFlavour') eq 'UNIMARC') {
31
        $fieldmatch = '2..';
32
    } else {
33
        $fieldmatch = '1..';
34
    }
35
    my $bibfield = $auth->field($fieldmatch);
36
    my $tag = $bibfield->tag();
37
    $tag =~ s/^./6/;
38
    $bibfield->update(tag => $tag);
39
    my $heading;
40
    ok(defined ($heading = C4::Heading->new_from_bib_field($bibfield, '')), "Creating heading from bib field");
41
42
    my $authmatch;
43
    my $fuzzy;
44
    ($authmatch, $fuzzy) = $linker->get_link($heading);
45
    is($authmatch, $authid, "Matched existing heading");
46
}
(-)a/t/db_dependent/lib/KohaTest/AuthoritiesMarc.pm (-2 lines)
Lines 24-30 sub methods : Test( 1 ) { Link Here
24
                      GetAuthorityXML 
24
                      GetAuthorityXML 
25
                      GetAuthority 
25
                      GetAuthority 
26
                      GetAuthType 
26
                      GetAuthType 
27
                      AUTHhtml2marc 
28
                      FindDuplicateAuthority 
27
                      FindDuplicateAuthority 
29
                      BuildSummary
28
                      BuildSummary
30
                      BuildUnimarcHierarchies
29
                      BuildUnimarcHierarchies
31
- 

Return to bug 7284