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

(-)a/C4/AuthoritiesMarc.pm (-37 / +48 lines)
Lines 96-110 sub GetAuthMARCFromKohaField { Link Here
96
=head2 SearchAuthorities 
96
=head2 SearchAuthorities 
97
97
98
  (\@finalresult, $nbresults)= &SearchAuthorities($tags, $and_or, 
98
  (\@finalresult, $nbresults)= &SearchAuthorities($tags, $and_or, 
99
     $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby)
99
     $excluding, $operator, $value, $offset,$length,$authtypecode,
100
     $sortby[, $skipmetadata])
100
101
101
returns ref to array result and count of results returned
102
returns ref to array result and count of results returned
102
103
103
=cut
104
=cut
104
105
105
sub SearchAuthorities {
106
sub SearchAuthorities {
106
    my ($tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby) = @_;
107
    my ($tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby,$skipmetadata) = @_;
107
#     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);
108
    my $dbh=C4::Context->dbh;
109
    my $dbh=C4::Context->dbh;
109
    if (C4::Context->preference('NoZebra')) {
110
    if (C4::Context->preference('NoZebra')) {
110
    
111
    
Lines 224-245 sub SearchAuthorities { Link Here
224
        {
225
        {
225
            if (@$value[$i]){
226
            if (@$value[$i]){
226
                if (@$tags[$i] eq "mainmainentry") {
227
                if (@$tags[$i] eq "mainmainentry") {
227
228
                    $attr =" \@attr 1=Heading-Main ";
228
                $attr =" \@attr 1=Heading-Main ";
229
                } elsif (@$tags[$i] eq "mainentry") {
229
230
                    $attr =" \@attr 1=Heading ";
230
                }elsif (@$tags[$i] eq "mainentry") {
231
                } elsif (@$tags[$i] eq "any") {
231
                $attr =" \@attr 1=Heading ";
232
                    $attr =" \@attr 1=Any ";
232
                }elsif (@$tags[$i] eq "any") {
233
                } elsif (@$tags[$i] eq "match") {
233
                $attr =" \@attr 1=Any ";
234
                    $attr =" \@attr 1=Match ";
234
                }else {
235
                } elsif (@$tags[$i] eq "match-heading") {
235
                $attr =" \@attr 1=Match ";
236
                    $attr =" \@attr 1=Match-heading ";
237
                } elsif (@$tags[$i] eq "see-from") {
238
                    $attr =" \@attr 1=Match-heading-see-from ";
239
                } elsif (@$tags[$i] eq "thesaurus") {
240
                    $attr =" \@attr 1=Subject-heading-thesaurus ";
236
                }
241
                }
237
                if (@$operator[$i] eq 'is') {
242
                if (@$operator[$i] eq 'is') {
238
                    $attr.=" \@attr 4=1  \@attr 5=100 ";##Phrase, No truncation,all of subfield field must match
243
                    $attr.=" \@attr 4=1  \@attr 5=100 ";##Phrase, No truncation,all of subfield field must match
239
                }elsif (@$operator[$i] eq "="){
244
                } elsif (@$operator[$i] eq "="){
240
                    $attr.=" \@attr 4=107 ";           #Number Exact match
245
                    $attr.=" \@attr 4=107 ";           #Number Exact match
241
                }elsif (@$operator[$i] eq "start"){
246
                } elsif (@$operator[$i] eq "start"){
242
                    $attr.=" \@attr 3=2 \@attr 4=1 \@attr 5=1 ";#Firstinfield Phrase, Right truncated
247
                    $attr.=" \@attr 3=2 \@attr 4=1 \@attr 5=1 ";#Firstinfield Phrase, Right truncated
248
                } elsif (@$operator[$i] eq "exact"){
249
                    $attr.=" \@attr 4=1  \@attr 5=100 \@attr 6=3 ";##Phrase, No truncation,all of subfield field must match
243
                } else {
250
                } else {
244
                    $attr .=" \@attr 5=1 \@attr 4=6 ";## Word list, right truncated, anywhere
251
                    $attr .=" \@attr 5=1 \@attr 4=6 ";## Word list, right truncated, anywhere
245
                }
252
                }
Lines 252-258 sub SearchAuthorities { Link Here
252
        }
259
        }
253
        ##Add how many queries generated
260
        ##Add how many queries generated
254
        if (defined $query && $query=~/\S+/){
261
        if (defined $query && $query=~/\S+/){
255
          $query= $and x $attr_cnt . $query . $q2;
262
          $query= $and x $attr_cnt . $query . (defined $q2 ? $q2 : '');
256
        } else {
263
        } else {
257
          $query= $q2;
264
          $query= $q2;
258
        }
265
        }
Lines 309-343 sub SearchAuthorities { Link Here
309
            my $separator=C4::Context->preference('authoritysep');
316
            my $separator=C4::Context->preference('authoritysep');
310
            $authrecord = MARC::File::USMARC::decode($marcdata);
317
            $authrecord = MARC::File::USMARC::decode($marcdata);
311
            my $authid=$authrecord->field('001')->data(); 
318
            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;
319
            my %newline;
325
            $newline{summary} = $summary;
326
            $newline{authid} = $authid;
320
            $newline{authid} = $authid;
327
            $newline{even} = $counter % 2;
321
            if (! $skipmetadata) {
328
            $newline{reported_tag} = $reported_tag;
322
                my $summary=BuildSummary($authrecord,$authid,$authtypecode);
323
                my $query_auth_tag = "SELECT auth_tag_to_report FROM auth_types WHERE authtypecode=?";
324
                my $sth = $dbh->prepare($query_auth_tag);
325
                $sth->execute($authtypecode);
326
                my $auth_tag_to_report = $sth->fetchrow;
327
                my $reported_tag;
328
                my $mainentry = $authrecord->field($auth_tag_to_report);
329
                if ($mainentry) {
330
                    foreach ($mainentry->subfields()) {
331
                        $reported_tag .='$'.$_->[0].$_->[1];
332
                    }
333
                }
334
                $newline{summary} = $summary;
335
                $newline{even} = $counter % 2;
336
                $newline{reported_tag} = $reported_tag;
337
            }
329
            $counter++;
338
            $counter++;
330
            push @finalresult, \%newline;
339
            push @finalresult, \%newline;
331
            }## while counter
340
            }## while counter
332
        ###
341
            ###
333
        for (my $z=0; $z<@finalresult; $z++){
342
            if (! $skipmetadata) {
334
                my  $count=CountUsage($finalresult[$z]{authid});
343
                for (my $z=0; $z<@finalresult; $z++){
335
                $finalresult[$z]{used}=$count;
344
                    my  $count=CountUsage($finalresult[$z]{authid});
336
        }# all $z's
345
                    $finalresult[$z]{used}=$count;
337
        
346
                }# all $z's
347
            }
348
338
        }## if nbresult
349
        }## if nbresult
339
        NOLUCK:
350
        NOLUCK:
340
        # $oAResult->destroy();
351
        $oAResult->destroy();
341
        # $oAuth[0]->destroy();
352
        # $oAuth[0]->destroy();
342
        
353
        
343
        return (\@finalresult, $nbresults);
354
        return (\@finalresult, $nbresults);
(-)a/C4/Biblio.pm (-8 / +15 lines)
Lines 35-40 use C4::Dates qw/format_date/; Link Here
35
use C4::Log;    # logaction
35
use C4::Log;    # logaction
36
use C4::ClassSource;
36
use C4::ClassSource;
37
use C4::Charset;
37
use C4::Charset;
38
use C4::Linker;
38
require C4::Heading;
39
require C4::Heading;
39
require C4::Serials;
40
require C4::Serials;
40
require C4::Items;
41
require C4::Items;
Lines 477-483 MARC record. Link Here
477
=cut
478
=cut
478
479
479
sub LinkBibHeadingsToAuthorities {
480
sub LinkBibHeadingsToAuthorities {
481
    my $linker = shift;
480
    my $bib = shift;
482
    my $bib = shift;
483
    my %results;
481
484
482
    my $num_headings_changed = 0;
485
    my $num_headings_changed = 0;
483
    foreach my $field ( $bib->fields() ) {
486
    foreach my $field ( $bib->fields() ) {
Lines 487-513 sub LinkBibHeadingsToAuthorities { Link Here
487
        # check existing $9
490
        # check existing $9
488
        my $current_link = $field->subfield('9');
491
        my $current_link = $field->subfield('9');
489
492
490
        # look for matching authorities
493
        if (defined $current_link && !C4::Context->preference('LinkerRelink')) {
491
        my $authorities = $heading->authorities();
494
            $results{'linked'}->{$heading->display_form()}++;
495
            next;
496
        }
492
497
493
        # want only one exact match
498
        my ($authid, $fuzzy) = $linker->get_link($heading);
494
        if ( $#{$authorities} == 0 ) {
499
        if ($authid) {
495
            my $authority = MARC::Record->new_from_usmarc( $authorities->[0] );
500
            $results{$fuzzy ? 'fuzzy' : 'linked'}->{$heading->display_form()}++;
496
            my $authid    = $authority->field('001')->data();
497
            next if defined $current_link and $current_link eq $authid;
501
            next if defined $current_link and $current_link eq $authid;
498
502
499
            $field->delete_subfield( code => '9' ) if defined $current_link;
503
            $field->delete_subfield( code => '9' ) if defined $current_link;
500
            $field->add_subfields( '9', $authid );
504
            $field->add_subfields( '9', $authid );
501
            $num_headings_changed++;
505
            $num_headings_changed++;
502
        } else {
506
        } else {
503
            if ( defined $current_link ) {
507
            if ( defined $current_link && C4::Context->preference('LinkerKeepStale')) {
508
                $results{'fuzzy'}->{$heading->display_form()}++;
509
            } else {
504
                $field->delete_subfield( code => '9' );
510
                $field->delete_subfield( code => '9' );
505
                $num_headings_changed++;
511
                $num_headings_changed++;
512
                $results{'unlinked'}->{$heading->display_form()}++;
506
            }
513
            }
507
        }
514
        }
508
515
509
    }
516
    }
510
    return $num_headings_changed;
517
    return $num_headings_changed, \%results;
511
}
518
}
512
519
513
=head2 GetRecordValue
520
=head2 GetRecordValue
(-)a/C4/Heading.pm (-31 / +49 lines)
Lines 23-29 use MARC::Record; Link Here
23
use MARC::Field;
23
use MARC::Field;
24
use C4::Context;
24
use C4::Context;
25
use C4::Heading::MARC21;
25
use C4::Heading::MARC21;
26
use C4::Search;
26
use C4::AuthoritiesMarc;
27
use Carp;
27
use Carp;
28
28
29
our $VERSION = 3.00;
29
our $VERSION = 3.00;
Lines 75-88 sub new_from_bib_field { Link Here
75
    return unless $marc_handler->valid_bib_heading_tag($tag);
75
    return unless $marc_handler->valid_bib_heading_tag($tag);
76
    my $self = {};
76
    my $self = {};
77
   
77
   
78
    ($self->{'auth_type'}, $self->{'subject_added_entry'}, $self->{'series_added_entry'}, $self->{'main_entry'},
78
    $self->{'field'} = $field;
79
     $self->{'thesaurus'}, $self->{'search_form'}, $self->{'display_form'}) =
79
    ($self->{'auth_type'}, $self->{'thesaurus'}, $self->{'search_form'},
80
     $self->{'display_form'}, $self->{'match_type'}) =
80
        $marc_handler->parse_heading($field);
81
        $marc_handler->parse_heading($field);
81
82
82
    bless $self, $class;
83
    bless $self, $class;
83
    return $self;
84
    return $self;
84
}
85
}
85
86
87
=head2 field
88
89
  my $field = $heading->field();
90
91
Return the MARC::Field the heading is based on.
92
93
=cut
94
95
sub field {
96
    my $self = shift;
97
    return $self->{'field'};
98
}
99
86
=head2 display_form
100
=head2 display_form
87
101
88
  my $display = $heading->display_form();
102
  my $display = $heading->display_form();
Lines 111-131 sub search_form { Link Here
111
125
112
=head2 authorities
126
=head2 authorities
113
127
114
  my $authorities = $heading->authorities;
128
  my $authorities = $heading->authorities([$skipmetadata]);
115
129
116
Return a list of authority records for this 
130
Return a list of authority records for this 
117
heading.
131
heading. If passed a true value for $skipmetadata,
132
SearchAuthorities will return only authids.
118
133
119
=cut
134
=cut
120
135
121
sub authorities {
136
sub authorities {
122
    my $self = shift;
137
    my $self = shift;
123
    my $query = qq(Match-heading,do-not-truncate,ext="$self->{'search_form'}");
138
    my $skipmetadata = shift;
124
    $query .= $self->_query_limiters();
139
    my ( $results, $total ) = _search($self, 'match-heading', $skipmetadata);
125
    my ($error, $results, $total_hits) = SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
126
    if (defined $error) {
127
        carp "Error:$error from search $query";
128
    }
129
    return $results;
140
    return $results;
130
}
141
}
131
142
Lines 140-175 that are a preferred form of the heading. Link Here
140
151
141
sub preferred_authorities {
152
sub preferred_authorities {
142
    my $self = shift;
153
    my $self = shift;
143
    my $query = "Match-heading-see-from,do-not-truncate,ext='$self->{'search_form'}'";
154
    my $skipmetadata = shift || undef;
144
    $query .= $self->_query_limiters();
155
    my ( $results, $total ) = _search('see-from', $skipmetadata);
145
    my ($error, $results, $total_hits) = SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
146
    if (defined $error) {
147
        carp "Error:$error from search $query";
148
    }
149
    return $results;
156
    return $results;
150
}
157
}
151
158
152
=head1 INTERNAL METHODS
159
=head1 INTERNAL METHODS
153
160
154
=head2 _query_limiters
161
=head2 _search
155
162
156
=cut
163
=cut
157
164
158
sub _query_limiters {
165
sub _search {
159
    my $self = shift;
166
    my $self = shift;
160
167
    my $index = shift || undef;
161
    my $limiters = " AND at='$self->{'auth_type'}'";
168
    my $skipmetadata = shift || undef;
162
    if ($self->{'subject_added_entry'}) {
169
    my @marclist;
163
        $limiters .= " AND Heading-use-subject-added-entry=a"; # FIXME -- is this properly in C4::Heading::MARC21?
170
    my @and_or;
164
        $limiters .= " AND Subject-heading-thesaurus=$self->{'thesaurus'}";
171
    my @excluding = [];
172
    my @operator;
173
    my @value;
174
175
    if ($index) {
176
        push @marclist, $index;
177
        push @and_or, 'and';
178
        push @operator, $self->{'match_type'};
179
        push @value, $self->{'search_form'};
165
    }
180
    }
166
    if ($self->{'series_added_entry'}) {
181
167
        $limiters .= " AND Heading-use-series-added-entry=a"; # FIXME -- is this properly in C4::Heading::MARC21?
182
#    if ($self->{'thesaurus'}) {
168
    }
183
#        push @marclist, 'thesaurus';
169
    if (not $self->{'subject_added_entry'} and not $self->{'series_added_entry'}) {
184
#        push @and_or, 'and';
170
        $limiters .= " AND Heading-use-main-or-added-entry=a" # FIXME -- is this properly in C4::Heading::MARC21?
185
#        push @excluding, '';
171
    }
186
#        push @operator, 'is';
172
    return $limiters;
187
#        push @value, $self->{'thesaurus'};
188
#    }
189
    return SearchAuthorities(\@marclist, \@and_or, \@excluding, \@operator, \@value,
190
        0, 20, $self->{'auth_type'}, '', $skipmetadata);
173
}
191
}
174
192
175
=head1 INTERNAL FUNCTIONS
193
=head1 INTERNAL FUNCTIONS
(-)a/C4/Heading/MARC21.pm (-6 / +15 lines)
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 124-137 sub parse_heading { Link Here
124
    my $field_info = $bib_heading_fields->{$tag};
124
    my $field_info = $bib_heading_fields->{$tag};
125
125
126
    my $auth_type = $field_info->{'auth_type'};
126
    my $auth_type = $field_info->{'auth_type'};
127
    my $subject = $field_info->{'subject'} ? 1 : 0;
127
    my $thesaurus = $tag =~ m/6../ ? _get_subject_thesaurus($field) : "lcsh"; # use 'lcsh' for names, UT, etc.
128
    my $series = $field_info->{'series'} ? 1 : 0;
129
    my $main_entry = $field_info->{'main_entry'} ? 1 : 0;
130
    my $thesaurus = $subject ? _get_subject_thesaurus($field) : "lcsh"; # use 'lcsh' for names, UT, etc.
131
    my $search_heading = _get_search_heading($field, $field_info->{'subfields'});
128
    my $search_heading = _get_search_heading($field, $field_info->{'subfields'});
132
    my $display_heading = _get_display_heading($field, $field_info->{'subfields'});
129
    my $display_heading = _get_display_heading($field, $field_info->{'subfields'});
133
130
134
    return ($auth_type, $subject, $series, $main_entry, $thesaurus, $search_heading, $display_heading);
131
    return ($auth_type, $thesaurus, $search_heading, $display_heading, 'exact');
135
}
132
}
136
133
137
=head1 INTERNAL FUNCTIONS
134
=head1 INTERNAL FUNCTIONS
Lines 182-187 sub _get_search_heading { Link Here
182
        my $code = $subfields[$i]->[0];
179
        my $code = $subfields[$i]->[0];
183
        my $code_re = quotemeta $code;
180
        my $code_re = quotemeta $code;
184
        my $value = $subfields[$i]->[1];
181
        my $value = $subfields[$i]->[1];
182
        $value =~ s/[-,.:=;!%\/]$//;
185
        next unless $subfields =~ qr/$code_re/;
183
        next unless $subfields =~ qr/$code_re/;
186
        if ($first) {
184
        if ($first) {
187
            $first = 0;
185
            $first = 0;
Lines 231-236 sub _get_display_heading { Link Here
231
    return $heading;
229
    return $heading;
232
}
230
}
233
231
232
# Additional limiters that we aren't using:
233
#    if ($self->{'subject_added_entry'}) {
234
#        $limiters .= " AND Heading-use-subject-added-entry=a";
235
#    }
236
#    if ($self->{'series_added_entry'}) {
237
#        $limiters .= " AND Heading-use-series-added-entry=a";
238
#    }
239
#    if (not $self->{'subject_added_entry'} and not $self->{'series_added_entry'}) {
240
#        $limiters .= " AND Heading-use-main-or-added-entry=a"
241
#    }
242
234
=head1 AUTHOR
243
=head1 AUTHOR
235
244
236
Koha Development Team <http://koha-community.org/>
245
Koha Development Team <http://koha-community.org/>
(-)a/C4/Linker.pm (+110 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
    if (defined $param->{'auth_limit'} && $param->{'auth_limit'}) {
61
        my $dbh = C4::Context->dbh;
62
        my $sql = "SELECT authid FROM auth_header WHERE $param->{'auth_limit'} ORDER BY authid ASC";
63
        my $sth = $dbh->prepare($sql);
64
        $sth->execute();
65
        while (my ($authid) = $sth->fetchrow_array()) {
66
            push @{$self->{'auths_to_link'}}, $authid;
67
        }
68
    }
69
70
    bless $self, $class;
71
    return $self;
72
}
73
74
=head2 _handle_auth_limit
75
76
    return $self->SUPER::_handle_auth_limit($authid), $fuzzy;
77
78
=back
79
80
Function to be called by subclasses to handle authority record limits.
81
82
=cut
83
84
sub _handle_auth_limit {
85
    my $self = shift;
86
    my $authid = shift;
87
88
    if (defined $self->{'auths_to_link'} && !grep {$_ eq $authid} @{$self->{'auths_to_link'}}) {
89
        undef $authid;
90
    }
91
    return $authid;
92
}
93
94
=head2 EXPORT
95
96
None by default.
97
98
=head1 SEE ALSO
99
100
C4::Linker::Default
101
102
=head1 AUTHOR
103
104
Jared Camins-Esakov, C & P Bibliography Services, E<lt>jcamins@cpbibliography.comE<gt>
105
106
=cut
107
108
1;
109
110
__END__
(-)a/C4/Linker/Default.pm (+73 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 C4::Heading;
24
25
use base qw(C4::Linker);
26
27
sub get_link {
28
    my $self = shift;
29
    my $heading = shift;
30
    my $behavior = shift || 'default';
31
    my $search_form = $heading->search_form();
32
    my $authid;
33
    my $fuzzy = 0;
34
35
    if ($self->{'cache'}->{$search_form}->{'cached'}) {
36
        $authid = $self->{'cache'}->{$search_form}->{'authid'};
37
        $fuzzy = $self->{'cache'}->{$search_form}->{'fuzzy'};
38
    } else {
39
        # look for matching authorities
40
        my $authorities = $heading->authorities(1); # $skipmetadata = true
41
42
        if ( $behavior eq 'default' && $#{$authorities} == 0 ) {
43
            $authid = $authorities->[0]->{'authid'};
44
        } elsif ($behavior eq 'first' && $#{$authorities} >= 0 ) {
45
            $authid = $authorities->[0]->{'authid'};
46
            $fuzzy = $#{$authorities} > 0;
47
        } elsif ($behavior eq 'last' && $#{$authorities} >= 0 ) {
48
            $authid = $authorities->[$#{$authorities}]->{'authid'};
49
            $fuzzy = $#{$authorities} > 0;
50
        }
51
52
        $self->{'cache'}->{$search_form}->{'cached'} = 1;
53
        $self->{'cache'}->{$search_form}->{'authid'} = $authid;
54
        $self->{'cache'}->{$search_form}->{'fuzzy'} = $fuzzy;
55
    }
56
    return $self->SUPER::_handle_auth_limit($authid), $fuzzy;
57
}
58
59
sub flip_heading {
60
    my $self = shift;
61
    my $heading = shift;
62
63
    # TODO: implement
64
}
65
66
1;
67
__END__
68
69
=head1 NAME
70
71
C4::Linker::Default - match only if there is a single matching auth
72
73
=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/etc/zebradb/marc_defs/marc21/authorities/authority-koha-indexdefs.xml (-8 / +24 lines)
Lines 93-101 authority-zebra-indexdefs.xsl` Link Here
93
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
93
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
94
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
94
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
95
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
95
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
96
  </kohaidx:index_heading>
97
  <kohaidx:index_match_heading tag="500" subfields="abcdefghjklmnopqrstvxyz" subdivisions="vxyz">
96
    <kohaidx:target_index>Match:w</kohaidx:target_index>
98
    <kohaidx:target_index>Match:w</kohaidx:target_index>
97
    <kohaidx:target_index>Match:p</kohaidx:target_index>
99
    <kohaidx:target_index>Match:p</kohaidx:target_index>
98
  </kohaidx:index_heading>
100
  </kohaidx:index_match_heading>
99
  
101
  
100
  <!-- Corporate name headings -->
102
  <!-- Corporate name headings -->
101
  <kohaidx:index_subfields tag="110" subfields="abcdefghklmnoprstvxyz">
103
  <kohaidx:index_subfields tag="110" subfields="abcdefghklmnoprstvxyz">
Lines 144-152 authority-zebra-indexdefs.xsl` Link Here
144
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
146
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
145
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
147
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
146
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
148
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
149
  </kohaidx:index_heading>
150
  <kohaidx:index_match_heading tag="510" subfields="abcdefghklmnoprstvxyz" subdivisions="vxyz">
147
    <kohaidx:target_index>Match:w</kohaidx:target_index>
151
    <kohaidx:target_index>Match:w</kohaidx:target_index>
148
    <kohaidx:target_index>Match:p</kohaidx:target_index>
152
    <kohaidx:target_index>Match:p</kohaidx:target_index>
149
  </kohaidx:index_heading>
153
  </kohaidx:index_match_heading>
150
  
154
  
151
  <!-- Meeting name -->
155
  <!-- Meeting name -->
152
  <kohaidx:index_subfields tag="111" subfields="acdefghjklnpqstvxyz">
156
  <kohaidx:index_subfields tag="111" subfields="acdefghjklnpqstvxyz">
Lines 195-203 authority-zebra-indexdefs.xsl` Link Here
195
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
199
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
196
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
200
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
197
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
201
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
202
  </kohaidx:index_heading>
203
  <kohaidx:index_match_heading tag="511" subfields="acdefghjklnpqstvxyz" subdivisions="vxyz">
198
    <kohaidx:target_index>Match:w</kohaidx:target_index>
204
    <kohaidx:target_index>Match:w</kohaidx:target_index>
199
    <kohaidx:target_index>Match:p</kohaidx:target_index>
205
    <kohaidx:target_index>Match:p</kohaidx:target_index>
200
  </kohaidx:index_heading>
206
  </kohaidx:index_match_heading>
201
  
207
  
202
  <!-- Uniform title -->
208
  <!-- Uniform title -->
203
  <kohaidx:index_subfields tag="130" subfields="adfghklmnoprstvxyz">
209
  <kohaidx:index_subfields tag="130" subfields="adfghklmnoprstvxyz">
Lines 246-254 authority-zebra-indexdefs.xsl` Link Here
246
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
252
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
247
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
253
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
248
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
254
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
255
  </kohaidx:index_heading>
256
  <kohaidx:index_match_heading tag="530" subfields="adfghklmnoprstvxyz" subdivisions="vxyz">
249
    <kohaidx:target_index>Match:w</kohaidx:target_index>
257
    <kohaidx:target_index>Match:w</kohaidx:target_index>
250
    <kohaidx:target_index>Match:p</kohaidx:target_index>
258
    <kohaidx:target_index>Match:p</kohaidx:target_index>
251
  </kohaidx:index_heading>
259
  </kohaidx:index_match_heading>
252
  
260
  
253
  <!-- Chronological term -->
261
  <!-- Chronological term -->
254
  <kohaidx:index_subfields tag="148" subfields="avxyz">
262
  <kohaidx:index_subfields tag="148" subfields="avxyz">
Lines 297-305 authority-zebra-indexdefs.xsl` Link Here
297
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
305
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
298
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
306
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
299
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
307
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
308
  </kohaidx:index_heading>
309
  <kohaidx:index_match_heading tag="548" subfields="avxyz" subdivisions="vxyz">
300
    <kohaidx:target_index>Match:w</kohaidx:target_index>
310
    <kohaidx:target_index>Match:w</kohaidx:target_index>
301
    <kohaidx:target_index>Match:p</kohaidx:target_index>
311
    <kohaidx:target_index>Match:p</kohaidx:target_index>
302
  </kohaidx:index_heading>
312
  </kohaidx:index_match_heading>
303
  
313
  
304
  
314
  
305
  <!-- Topical term -->
315
  <!-- Topical term -->
Lines 349-357 authority-zebra-indexdefs.xsl` Link Here
349
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
359
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
350
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
360
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
351
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
361
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
362
  </kohaidx:index_heading>
363
  <kohaidx:index_match_heading tag="550" subfields="abvxyz" subdivisions="vxyz">
352
    <kohaidx:target_index>Match:w</kohaidx:target_index>
364
    <kohaidx:target_index>Match:w</kohaidx:target_index>
353
    <kohaidx:target_index>Match:p</kohaidx:target_index>
365
    <kohaidx:target_index>Match:p</kohaidx:target_index>
354
  </kohaidx:index_heading>
366
  </kohaidx:index_match_heading>
355
  
367
  
356
  <!-- Geographic name -->
368
  <!-- Geographic name -->
357
  <kohaidx:index_subfields tag="151" subfields="avxyz">
369
  <kohaidx:index_subfields tag="151" subfields="avxyz">
Lines 400-408 authority-zebra-indexdefs.xsl` Link Here
400
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
412
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
401
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
413
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
402
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
414
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
415
  </kohaidx:index_heading>
416
  <kohaidx:index_match_heading tag="551" subfields="avxyz" subdivisions="vxyz">
403
    <kohaidx:target_index>Match:w</kohaidx:target_index>
417
    <kohaidx:target_index>Match:w</kohaidx:target_index>
404
    <kohaidx:target_index>Match:p</kohaidx:target_index>
418
    <kohaidx:target_index>Match:p</kohaidx:target_index>
405
  </kohaidx:index_heading>
419
  </kohaidx:index_match_heading>
406
  
420
  
407
  <!-- Genre/form term -->
421
  <!-- Genre/form term -->
408
  <kohaidx:index_subfields tag="155" subfields="avxyz">
422
  <kohaidx:index_subfields tag="155" subfields="avxyz">
Lines 451-459 authority-zebra-indexdefs.xsl` Link Here
451
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
465
    <kohaidx:target_index>See-also-from:w</kohaidx:target_index>
452
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
466
    <kohaidx:target_index>See-also-from:p</kohaidx:target_index>
453
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
467
    <kohaidx:target_index>See-also-from:s</kohaidx:target_index>
468
  </kohaidx:index_heading>
469
  <kohaidx:index_match_heading tag="555" subfields="avxyz" subdivisions="vxyz">
454
    <kohaidx:target_index>Match:w</kohaidx:target_index>
470
    <kohaidx:target_index>Match:w</kohaidx:target_index>
455
    <kohaidx:target_index>Match:p</kohaidx:target_index>
471
    <kohaidx:target_index>Match:p</kohaidx:target_index>
456
  </kohaidx:index_heading>
472
  </kohaidx:index_match_heading>
457
  
473
  
458
  <!-- General subdivision -->
474
  <!-- General subdivision -->
459
  <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 (-40 / +465 lines)
Lines 213-222 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
213
    </z:index>
213
    </z:index>
214
  </xslo:template>
214
  </xslo:template>
215
  <xslo:template mode="index_heading" match="marc:datafield[@tag='500']">
215
  <xslo:template mode="index_heading" match="marc:datafield[@tag='500']">
216
    <z:index name="Personal-name-see-also-from:w Personal-name-see-also-from:p Personal-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
216
    <z:index name="Personal-name-see-also-from:w Personal-name-see-also-from:p Personal-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
217
      <xslo:variable name="raw_heading">
217
      <xslo:variable name="raw_heading">
218
        <xslo:for-each select="marc:subfield">
218
        <xslo:for-each select="marc:subfield">
219
          <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Personal-name-see-also-from:w Personal-name-see-also-from:p Personal-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
219
          <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Personal-name-see-also-from:w Personal-name-see-also-from:p Personal-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
220
            <xslo:if test="position() &gt; 1">
220
            <xslo:if test="position() &gt; 1">
221
              <xslo:choose>
221
              <xslo:choose>
222
                <xslo:when test="contains('vxyz', @code)">
222
                <xslo:when test="contains('vxyz', @code)">
Lines 299-308 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
299
    </z:index>
299
    </z:index>
300
  </xslo:template>
300
  </xslo:template>
301
  <xslo:template mode="index_heading" match="marc:datafield[@tag='510']">
301
  <xslo:template mode="index_heading" match="marc:datafield[@tag='510']">
302
    <z:index name="Corporate-name-see-also-from:w Corporate-name-see-also-from:p Corporate-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
302
    <z:index name="Corporate-name-see-also-from:w Corporate-name-see-also-from:p Corporate-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
303
      <xslo:variable name="raw_heading">
303
      <xslo:variable name="raw_heading">
304
        <xslo:for-each select="marc:subfield">
304
        <xslo:for-each select="marc:subfield">
305
          <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Corporate-name-see-also-from:w Corporate-name-see-also-from:p Corporate-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
305
          <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Corporate-name-see-also-from:w Corporate-name-see-also-from:p Corporate-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
306
            <xslo:if test="position() &gt; 1">
306
            <xslo:if test="position() &gt; 1">
307
              <xslo:choose>
307
              <xslo:choose>
308
                <xslo:when test="contains('vxyz', @code)">
308
                <xslo:when test="contains('vxyz', @code)">
Lines 385-394 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
385
    </z:index>
385
    </z:index>
386
  </xslo:template>
386
  </xslo:template>
387
  <xslo:template mode="index_heading" match="marc:datafield[@tag='511']">
387
  <xslo:template mode="index_heading" match="marc:datafield[@tag='511']">
388
    <z:index name="Meeting-name-see-also-from:w Meeting-name-see-also-from:p Meeting-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
388
    <z:index name="Meeting-name-see-also-from:w Meeting-name-see-also-from:p Meeting-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
389
      <xslo:variable name="raw_heading">
389
      <xslo:variable name="raw_heading">
390
        <xslo:for-each select="marc:subfield">
390
        <xslo:for-each select="marc:subfield">
391
          <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Meeting-name-see-also-from:w Meeting-name-see-also-from:p Meeting-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
391
          <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Meeting-name-see-also-from:w Meeting-name-see-also-from:p Meeting-name-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
392
            <xslo:if test="position() &gt; 1">
392
            <xslo:if test="position() &gt; 1">
393
              <xslo:choose>
393
              <xslo:choose>
394
                <xslo:when test="contains('vxyz', @code)">
394
                <xslo:when test="contains('vxyz', @code)">
Lines 471-480 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
471
    </z:index>
471
    </z:index>
472
  </xslo:template>
472
  </xslo:template>
473
  <xslo:template mode="index_heading" match="marc:datafield[@tag='530']">
473
  <xslo:template mode="index_heading" match="marc:datafield[@tag='530']">
474
    <z:index name="Title-uniform-see-also-from:w Title-uniform-see-also-from:p Title-uniform-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
474
    <z:index name="Title-uniform-see-also-from:w Title-uniform-see-also-from:p Title-uniform-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
475
      <xslo:variable name="raw_heading">
475
      <xslo:variable name="raw_heading">
476
        <xslo:for-each select="marc:subfield">
476
        <xslo:for-each select="marc:subfield">
477
          <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Title-uniform-see-also-from:w Title-uniform-see-also-from:p Title-uniform-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
477
          <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Title-uniform-see-also-from:w Title-uniform-see-also-from:p Title-uniform-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
478
            <xslo:if test="position() &gt; 1">
478
            <xslo:if test="position() &gt; 1">
479
              <xslo:choose>
479
              <xslo:choose>
480
                <xslo:when test="contains('vxyz', @code)">
480
                <xslo:when test="contains('vxyz', @code)">
Lines 557-566 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
557
    </z:index>
557
    </z:index>
558
  </xslo:template>
558
  </xslo:template>
559
  <xslo:template mode="index_heading" match="marc:datafield[@tag='548']">
559
  <xslo:template mode="index_heading" match="marc:datafield[@tag='548']">
560
    <z:index name="Chronological-term-see-also-from:w Chronological-term-see-also-from:p Chronological-term-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
560
    <z:index name="Chronological-term-see-also-from:w Chronological-term-see-also-from:p Chronological-term-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
561
      <xslo:variable name="raw_heading">
561
      <xslo:variable name="raw_heading">
562
        <xslo:for-each select="marc:subfield">
562
        <xslo:for-each select="marc:subfield">
563
          <xslo:if test="contains('avxyz', @code)" name="Chronological-term-see-also-from:w Chronological-term-see-also-from:p Chronological-term-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
563
          <xslo:if test="contains('avxyz', @code)" name="Chronological-term-see-also-from:w Chronological-term-see-also-from:p Chronological-term-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
564
            <xslo:if test="position() &gt; 1">
564
            <xslo:if test="position() &gt; 1">
565
              <xslo:choose>
565
              <xslo:choose>
566
                <xslo:when test="contains('vxyz', @code)">
566
                <xslo:when test="contains('vxyz', @code)">
Lines 643-652 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
643
    </z:index>
643
    </z:index>
644
  </xslo:template>
644
  </xslo:template>
645
  <xslo:template mode="index_heading" match="marc:datafield[@tag='550']">
645
  <xslo:template mode="index_heading" match="marc:datafield[@tag='550']">
646
    <z:index name="Subject-topical-see-also-from:w Subject-topical-see-also-from:p Subject-topical-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
646
    <z:index name="Subject-topical-see-also-from:w Subject-topical-see-also-from:p Subject-topical-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
647
      <xslo:variable name="raw_heading">
647
      <xslo:variable name="raw_heading">
648
        <xslo:for-each select="marc:subfield">
648
        <xslo:for-each select="marc:subfield">
649
          <xslo:if test="contains('abvxyz', @code)" name="Subject-topical-see-also-from:w Subject-topical-see-also-from:p Subject-topical-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
649
          <xslo:if test="contains('abvxyz', @code)" name="Subject-topical-see-also-from:w Subject-topical-see-also-from:p Subject-topical-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
650
            <xslo:if test="position() &gt; 1">
650
            <xslo:if test="position() &gt; 1">
651
              <xslo:choose>
651
              <xslo:choose>
652
                <xslo:when test="contains('vxyz', @code)">
652
                <xslo:when test="contains('vxyz', @code)">
Lines 729-738 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
729
    </z:index>
729
    </z:index>
730
  </xslo:template>
730
  </xslo:template>
731
  <xslo:template mode="index_heading" match="marc:datafield[@tag='551']">
731
  <xslo:template mode="index_heading" match="marc:datafield[@tag='551']">
732
    <z:index name="Name-geographic-see-also-from:w Name-geographic-see-also-from:p Name-geographic-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
732
    <z:index name="Name-geographic-see-also-from:w Name-geographic-see-also-from:p Name-geographic-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
733
      <xslo:variable name="raw_heading">
733
      <xslo:variable name="raw_heading">
734
        <xslo:for-each select="marc:subfield">
734
        <xslo:for-each select="marc:subfield">
735
          <xslo:if test="contains('avxyz', @code)" name="Name-geographic-see-also-from:w Name-geographic-see-also-from:p Name-geographic-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
735
          <xslo:if test="contains('avxyz', @code)" name="Name-geographic-see-also-from:w Name-geographic-see-also-from:p Name-geographic-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
736
            <xslo:if test="position() &gt; 1">
736
            <xslo:if test="position() &gt; 1">
737
              <xslo:choose>
737
              <xslo:choose>
738
                <xslo:when test="contains('vxyz', @code)">
738
                <xslo:when test="contains('vxyz', @code)">
Lines 815-824 authority-zebra-indexdefs.xsl` (substituting the appropriate file names). Link Here
815
    </z:index>
815
    </z:index>
816
  </xslo:template>
816
  </xslo:template>
817
  <xslo:template mode="index_heading" match="marc:datafield[@tag='555']">
817
  <xslo:template mode="index_heading" match="marc:datafield[@tag='555']">
818
    <z:index name="Term-genre-form-see-also-from:w Term-genre-form-see-also-from:p Term-genre-form-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
818
    <z:index name="Term-genre-form-see-also-from:w Term-genre-form-see-also-from:p Term-genre-form-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
819
      <xslo:variable name="raw_heading">
819
      <xslo:variable name="raw_heading">
820
        <xslo:for-each select="marc:subfield">
820
        <xslo:for-each select="marc:subfield">
821
          <xslo:if test="contains('avxyz', @code)" name="Term-genre-form-see-also-from:w Term-genre-form-see-also-from:p Term-genre-form-see-also-from:s See-also-from:w See-also-from:p See-also-from:s Match:w Match:p">
821
          <xslo:if test="contains('avxyz', @code)" name="Term-genre-form-see-also-from:w Term-genre-form-see-also-from:p Term-genre-form-see-also-from:s See-also-from:w See-also-from:p See-also-from:s">
822
            <xslo:if test="position() &gt; 1">
822
            <xslo:if test="position() &gt; 1">
823
              <xslo:choose>
823
              <xslo:choose>
824
                <xslo:when test="contains('vxyz', @code)">
824
                <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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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/installer/data/mysql/atomicupdate/bug_7284_authority_linking_pt1 (+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("INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerModule','Default','Chooses which linker module to use (see documentation).','Default|FirstMatchLastMatch','Choice');");
7
$dbh->do("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');");
8
$dbh->do("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');");
9
print "Upgrade done (Configured bug 7284, improved authority matching)\n";
(-)a/installer/data/mysql/sysprefs.sql (-1 / +4 lines)
Lines 329-332 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
329
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('OpacKohaUrl','1',"Show 'Powered by Koha' text on OPAC footer.",NULL,NULL);
329
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('OpacKohaUrl','1',"Show 'Powered by Koha' text on OPAC footer.",NULL,NULL);
330
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('EasyAnalyticalRecords','0','If on, display in the catalogue screens tools to easily setup analytical record relationships','','YesNo');
330
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('EasyAnalyticalRecords','0','If on, display in the catalogue screens tools to easily setup analytical record relationships','','YesNo');
331
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacShowRecentComments',0,'If ON a link to recent comments will appear in the OPAC masthead',NULL,'YesNo');
331
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacShowRecentComments',0,'If ON a link to recent comments will appear in the OPAC masthead',NULL,'YesNo');
332
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('CircAutoPrintQuickSlip', '1', 'Choose what should happen when an empty barcode field is submitted in circulation: Display a print quick slip window or Clear the screen.',NULL,'YesNo');
332
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('CircAutoPrintQuickSlip', '1', 'Choose what should happen when an empty barcode field is submitted in circulation: Display a print quick slip window or Clear the screen.',NULL,'YesNo');
333
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerModule','Default','Chooses which linker module to use (see documentation).','Default|FirstMatch|LastMatch','Choice');
334
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');
335
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');
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/authorities.pref (-28 / +53 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
            - pref: dontmerge
13
          choices:
13
              default: yes
14
              yes: "Don't"
14
              choices:
15
              no: Do
15
                  yes: "Don't"
16
        - automatically update attached biblios when changing an authority record. If this is off, please ask your administrator to enable the merge_authorities.pl cronjob.
16
                  no: Do
17
    -
17
            - automatically update attached biblios when changing an authority record. If this is off, please ask your administrator to enable the merge_authorities.pl cronjob.
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
        -
19
        - pref: MARCAuthorityControlField008
19
            - 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).
20
          default: "|| aca||aabn           | a|a     d"
20
            - pref: MARCAuthorityControlField008
21
          type: textarea
21
              default: "|| aca||aabn           | a|a     d"
22
          class: code
22
              type: textarea
23
    -
23
              class: code
24
        - pref: UseAuthoritiesForTracings
24
        -
25
          default: yes
25
            - pref: UseAuthoritiesForTracings
26
          choices:
26
              default: yes
27
              yes: Use
27
              choices:
28
              no: "Don't use"
28
                  yes: Use
29
        - authority record numbers instead of text strings for searches from subject tracings.
29
                  no: "Don't use"
30
            - authority record numbers instead of text strings for searches from subject tracings.
31
    Linker:
32
        -
33
            - Use the 
34
            - pref: LinkerModule
35
              default: Default
36
              choices:
37
                  Default: Default
38
                  FirstMatch: "First Match"
39
                  LastMatch: "Last Match"
40
            - linker module for matching headings to authority records.
41
        -
42
            - pref: LinkerRelink
43
              default: yes
44
              choices:
45
                  yes: Do
46
                  no: "Do not"
47
            - relink headings that have previously been linked to authority records.
48
        -
49
            - pref: LinkerKeepStale
50
              default: no
51
              choices:
52
                  yes: Do
53
                  no: "Do not"
54
            - keep existing links to authority records for headings where the linker is unable to find a match.
(-)a/misc/link_bibs_to_authorities.pl (-36 / +185 lines)
Lines 12-55 BEGIN { Link Here
12
use C4::Context;
12
use C4::Context;
13
use C4::Biblio;
13
use C4::Biblio;
14
use Getopt::Long;
14
use Getopt::Long;
15
use Pod::Usage;
16
use Data::Dumper;
17
18
sub usage {
19
    pod2usage( -verbose => 2 );
20
    exit;
21
}
15
22
16
$| = 1;
23
$| = 1;
17
24
18
# command-line parameters
25
# command-line parameters
19
my $verbose   = 0;
26
my $verbose   = 0;
27
my $link_report = 0;
20
my $test_only = 0;
28
my $test_only = 0;
21
my $want_help = 0;
29
my $want_help = 0;
30
my $auth_limit;
31
my $bib_limit;
32
my $commit = 100;
22
33
23
my $result = GetOptions(
34
my $result = GetOptions(
24
    'verbose'       => \$verbose,
35
    'v|verbose'       => \$verbose,
25
    'test'          => \$test_only,
36
    't|test'          => \$test_only,
26
    'h|help'        => \$want_help
37
    'l|link-report'   => \$link_report,
38
    'a|auth-limit=s'  => \$auth_limit,
39
    'b|bib-limit=s'   => \$bib_limit,
40
    'c|commit=i'      => \$commit,
41
    'h|help'          => \$want_help
27
);
42
);
28
43
44
binmode(STDOUT, ":utf8");
45
29
if (not $result or $want_help) {
46
if (not $result or $want_help) {
30
    print_usage();
47
    usage();
31
    exit 0;
32
}
48
}
33
49
50
my $linker_module = "C4::Linker::" . (C4::Context->preference("LinkerModule") || 'Default');
51
eval {
52
    eval "require $linker_module";
53
};
54
if ($@){
55
    $linker_module = 'C4::Linker::Default';
56
    eval "require $linker_module";
57
}
58
if ($@) {
59
    die "Unable to load linker module. Aborting.";
60
}
61
62
my $linker = $linker_module->new( {'auth_limit' => $auth_limit} );
63
34
my $num_bibs_processed = 0;
64
my $num_bibs_processed = 0;
35
my $num_bibs_modified = 0;
65
my $num_bibs_modified = 0;
36
my $num_bad_bibs = 0;
66
my $num_bad_bibs = 0;
67
my %unlinked_headings;
68
my %linked_headings;
69
my %fuzzy_headings;
37
my $dbh = C4::Context->dbh;
70
my $dbh = C4::Context->dbh;
38
$dbh->{AutoCommit} = 0;
71
$dbh->{AutoCommit} = 0;
39
process_bibs();
72
process_bibs($linker, $bib_limit, $auth_limit, $commit);
40
$dbh->commit();
73
$dbh->commit();
41
74
42
exit 0;
75
exit 0;
43
76
44
sub process_bibs {
77
sub process_bibs {
45
    my $sql = "SELECT biblionumber FROM biblio ORDER BY biblionumber ASC";
78
    my ($linker, $bib_limit, $auth_limit, $commit) = @_;
79
    my $bib_where = '';
80
    if ($bib_limit) {
81
        $bib_where = "WHERE $bib_limit";
82
    }
83
    my $sql = "SELECT biblionumber FROM biblio $bib_where ORDER BY biblionumber ASC";
46
    my $sth = $dbh->prepare($sql);
84
    my $sth = $dbh->prepare($sql);
47
    $sth->execute();
85
    $sth->execute();
48
    while (my ($biblionumber) = $sth->fetchrow_array()) {
86
    while (my ($biblionumber) = $sth->fetchrow_array()) {
49
        $num_bibs_processed++;
87
        $num_bibs_processed++;
50
        process_bib($biblionumber);
88
        process_bib($linker, $biblionumber);
51
89
52
        if (not $test_only and ($num_bibs_processed % 100) == 0) {
90
        if (not $test_only and ($num_bibs_processed % $commit) == 0) {
53
            print_progress_and_commit($num_bibs_processed);
91
            print_progress_and_commit($num_bibs_processed);
54
        }
92
        }
55
    }
93
    }
Lines 58-74 sub process_bibs { Link Here
58
        $dbh->commit;
96
        $dbh->commit;
59
    }
97
    }
60
98
99
    my $headings_linked = 0;
100
    my $headings_unlinked = 0;
101
    my $headings_fuzzy = 0;
102
    for (values %linked_headings) { $headings_linked += $_; };
103
    for (values %unlinked_headings) { $headings_unlinked += $_; };
104
    for (values %fuzzy_headings) { $headings_fuzzy += $_; };
105
61
    print <<_SUMMARY_;
106
    print <<_SUMMARY_;
62
107
63
Bib authority heading linking report
108
Bib authority heading linking report
64
------------------------------------
109
=======================================================
65
Number of bibs checked:       $num_bibs_processed
110
Linker module:                          $linker_module
66
Number of bibs modified:      $num_bibs_modified
111
Number of bibs checked:                 $num_bibs_processed
67
Number of bibs with errors:   $num_bad_bibs
112
Number of bibs modified:                $num_bibs_modified
113
Number of bibs with errors:             $num_bad_bibs
114
Number of headings linked:              $headings_linked
115
Number of headings unlinked:            $headings_unlinked
116
Number of headings fuzzily linked:      $headings_fuzzy
68
_SUMMARY_
117
_SUMMARY_
118
    print "****  Ran in test mode only  ****\n" if $test_only;
119
120
    if ($link_report) {
121
        my @keys;
122
        print <<_LINKED_HEADER_;
123
        
124
Linked headings (from most frequent to least):
125
-------------------------------------------------------
126
127
_LINKED_HEADER_
128
129
        @keys = sort { $linked_headings{$b} <=> $linked_headings{$a} or "\L$a" cmp "\L$b" } keys %linked_headings;
130
        foreach my $key (@keys) {
131
            print "$key:\t" . $linked_headings{$key} . " occurrences\n"
132
        }
133
134
        print <<_UNLINKED_HEADER_;
135
        
136
Unlinked headings (from most frequent to least):
137
-------------------------------------------------------
138
139
_UNLINKED_HEADER_
140
141
        @keys = sort { $unlinked_headings{$b} <=> $unlinked_headings{$a} or "\L$a" cmp "\L$b" } keys %unlinked_headings;
142
        foreach my $key (@keys) {
143
            print "$key:\t" . $unlinked_headings{$key} . " occurrences\n"
144
        }
145
146
        print <<_FUZZY_HEADER_;
147
        
148
Fuzzily-matched headings (from most frequent to least):
149
-------------------------------------------------------
150
151
_FUZZY_HEADER_
152
153
        @keys = sort { $fuzzy_headings{$b} <=> $fuzzy_headings{$a} or "\L$a" cmp "\L$b" } keys %fuzzy_headings;
154
        foreach my $key (@keys) {
155
            print "$key:\t" . $fuzzy_headings{$key} . " occurrences\n"
156
        }
157
        print <<_SUMMARY2_;
158
159
160
Printing out summary report again since your link
161
report may have been very long...
162
163
Bib authority heading linking report (duplicate)
164
=======================================================
165
Linker module:                          $linker_module
166
Number of bibs checked:                 $num_bibs_processed
167
Number of bibs modified:                $num_bibs_modified
168
Number of bibs with errors:             $num_bad_bibs
169
Number of headings linked:              $headings_linked
170
Number of headings unlinked:            $headings_unlinked
171
Number of headings fuzzily linked:      $headings_fuzzy
172
_SUMMARY2_
173
        print "****  Ran in test mode only  ****\n" if $test_only;
174
    }
69
}
175
}
70
176
71
sub process_bib {
177
sub process_bib {
178
    my $linker = shift;
72
    my $biblionumber = shift;
179
    my $biblionumber = shift;
73
180
74
    my $bib = GetMarcBiblio($biblionumber);
181
    my $bib = GetMarcBiblio($biblionumber);
Lines 78-84 sub process_bib { Link Here
78
        return;
185
        return;
79
    }
186
    }
80
187
81
    my $headings_changed = LinkBibHeadingsToAuthorities($bib);
188
    my ($headings_changed, $results) = LinkBibHeadingsToAuthorities($linker, $bib);
189
    foreach my $key (keys %{$results->{'unlinked'}}) {
190
        $unlinked_headings{$key} += $results->{'unlinked'}->{$key};
191
    }
192
    foreach my $key (keys %{$results->{'linked'}}) {
193
        $linked_headings{$key} += $results->{'linked'}->{$key};
194
    }
195
    foreach my $key (keys %{$results->{'fuzzy'}}) {
196
        $fuzzy_headings{$key} += $results->{'fuzzy'}->{$key};
197
    }
82
198
83
    if ($headings_changed) {   
199
    if ($headings_changed) {   
84
        if ($verbose) {
200
        if ($verbose) {
Lines 86-96 sub process_bib { Link Here
86
            print "Bib $biblionumber ($title): $headings_changed headings changed\n";
202
            print "Bib $biblionumber ($title): $headings_changed headings changed\n";
87
        }
203
        }
88
        if (not $test_only) {
204
        if (not $test_only) {
89
            # delete any item tags
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));
205
            ModBiblio($bib, $biblionumber, GetFrameworkCode($biblionumber));
95
            $num_bibs_modified++;
206
            $num_bibs_modified++;
96
        }
207
        }
Lines 103-122 sub print_progress_and_commit { Link Here
103
    print "... processed $recs records\n";
214
    print "... processed $recs records\n";
104
}
215
}
105
216
106
sub print_usage {
217
=head1 NAME
107
    print <<_USAGE_;
218
108
$0: link headings in bib records to authorities.
219
link_bibs_to_authorities.pl
109
220
110
This batch job checks each bib record in the Koha
221
=head1 SYNOPSIS
111
database and attempts to link each of its headings
222
112
to the matching authority record.
223
  link_bibs_to_authorities.pl
113
224
  link_bibs_to_authorities.pl -v
114
Parameters:
225
  link_bibs_to_authorities.pl -l
115
    --verbose               print the number of headings changed
226
  link_bibs_to_authorities.pl --commit=1000
116
                            for each bib
227
  link_bibs_to_authorities.pl --auth-limit=STRING
117
    --test                  only test the authority linking
228
  link_bibs_to_authorities.pl --bib-limit=STRING
118
                            and report the results; do not
229
119
                            change the bib records.
230
=head1 DESCRIPTION
120
    --help or -h            show this message.
231
121
_USAGE_
232
This batch job checks each bib record in the Koha database and attempts to link
122
}
233
each of its headings to the matching authority record.
234
235
=over 8
236
237
=item B<--help>
238
239
Prints this help
240
241
=item B<-v|--verbose>
242
243
Provide verbose log information (print the number of headings changed for each
244
bib record).
245
246
=item B<-l|--link-report>
247
248
Provide a report of all the headings that were processed: which were matched,
249
which were not, etc.
250
251
=item B<--auth-limit=S>
252
253
Only process those headings which match an authority record that matches the
254
user-specified WHERE clause.
255
256
=item B<--bib-limit=S>
257
258
Only process those bib records that match the user-specified WHERE clause.
259
260
=item B<--commit=N>
261
262
Commit the results to the database after every N records are processed.
263
264
=item B<--test>
265
266
Only test the authority linking and report the results; do not change the bib
267
records.
268
269
=back
270
271
=cut
(-)a/t/db_dependent/Linker_FirstMatch.t (-1 / +46 lines)
Line 0 Link Here
0
- 
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
}

Return to bug 7284