# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
use strict;
-#use warnings; FIXME - Bug 2505
+use warnings;
use C4::Context;
-use C4::Koha;
use MARC::Record;
use C4::Biblio;
use C4::Search;
&GetAuthType
&GetAuthTypeCode
&GetAuthMARCFromKohaField
- &AUTHhtml2marc
&AddAuthority
&ModAuthority
=head2 SearchAuthorities
(\@finalresult, $nbresults)= &SearchAuthorities($tags, $and_or,
- $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby)
+ $excluding, $operator, $value, $offset,$length,$authtypecode,
+ $sortby[, $skipmetadata])
returns ref to array result and count of results returned
=cut
sub SearchAuthorities {
- my ($tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby) = @_;
-# warn "CALL : $tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby";
+ my ($tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby,$skipmetadata) = @_;
+ # warn Dumper($tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode,$sortby);
my $dbh=C4::Context->dbh;
if (C4::Context->preference('NoZebra')) {
for(my $i = 0 ; $i <= $#{$value} ; $i++)
{
if (@$value[$i]){
- if (@$tags[$i] eq "mainmainentry") {
-
- $attr =" \@attr 1=Heading-Main ";
-
- }elsif (@$tags[$i] eq "mainentry") {
- $attr =" \@attr 1=Heading ";
- }else{
- $attr =" \@attr 1=Any ";
+ if ( @$tags[$i] eq "mainmainentry" ) {
+ $attr = " \@attr 1=Heading-Main ";
}
- if (@$operator[$i] eq 'is') {
- $attr.=" \@attr 4=1 \@attr 5=100 ";##Phrase, No truncation,all of subfield field must match
- }elsif (@$operator[$i] eq "="){
- $attr.=" \@attr 4=107 "; #Number Exact match
- }elsif (@$operator[$i] eq "start"){
- $attr.=" \@attr 3=2 \@attr 4=1 \@attr 5=1 ";#Firstinfield Phrase, Right truncated
- } else {
- $attr .=" \@attr 5=1 \@attr 4=6 ";## Word list, right truncated, anywhere
+ elsif ( @$tags[$i] eq "mainentry" ) {
+ $attr = " \@attr 1=Heading ";
+ }
+ elsif ( @$tags[$i] eq "any" ) {
+ $attr = " \@attr 1=Any ";
+ }
+ elsif ( @$tags[$i] eq "match" ) {
+ $attr = " \@attr 1=Match ";
+ }
+ elsif ( @$tags[$i] eq "match-heading" ) {
+ $attr = " \@attr 1=Match-heading ";
+ }
+ elsif ( @$tags[$i] eq "see-from" ) {
+ $attr = " \@attr 1=Match-heading-see-from ";
+ }
+ elsif ( @$tags[$i] eq "thesaurus" ) {
+ $attr = " \@attr 1=Subject-heading-thesaurus ";
+ }
+ if ( @$operator[$i] eq 'is' ) {
+ $attr .= " \@attr 4=1 \@attr 5=100 "
+ ; ##Phrase, No truncation,all of subfield field must match
+ }
+ elsif ( @$operator[$i] eq "=" ) {
+ $attr .= " \@attr 4=107 "; #Number Exact match
+ }
+ elsif ( @$operator[$i] eq "start" ) {
+ $attr .= " \@attr 3=2 \@attr 4=1 \@attr 5=1 "
+ ; #Firstinfield Phrase, Right truncated
+ }
+ elsif ( @$operator[$i] eq "exact" ) {
+ $attr .= " \@attr 4=1 \@attr 5=100 \@attr 6=3 "
+ ; ##Phrase, No truncation,all of subfield field must match
+ }
+ else {
+ $attr .= " \@attr 5=1 \@attr 4=6 "
+ ; ## Word list, right truncated, anywhere
}
@$value[$i] =~ s/"/\\"/g; # Escape the double-quotes in the search value
$attr =$attr."\"".@$value[$i]."\"";
}#if value
}
##Add how many queries generated
- if ($query=~/\S+/){
- $query= $and x $attr_cnt . $query . $q2;
+ if (defined $query && $query=~/\S+/){
+ $query= $and x $attr_cnt . $query . (defined $q2 ? $q2 : '');
} else {
$query= $q2;
}
my $separator=C4::Context->preference('authoritysep');
$authrecord = MARC::File::USMARC::decode($marcdata);
my $authid=$authrecord->field('001')->data();
- my $summary=BuildSummary($authrecord,$authid,$authtypecode);
- my $query_auth_tag = "SELECT auth_tag_to_report FROM auth_types WHERE authtypecode=?";
- my $sth = $dbh->prepare($query_auth_tag);
- $sth->execute($authtypecode);
- my $auth_tag_to_report = $sth->fetchrow;
- my $reported_tag;
- my $mainentry = $authrecord->field($auth_tag_to_report);
- if ($mainentry) {
- foreach ($mainentry->subfields()) {
- $reported_tag .='$'.$_->[0].$_->[1];
- }
- }
my %newline;
- $newline{summary} = $summary;
$newline{authid} = $authid;
- $newline{even} = $counter % 2;
- $newline{reported_tag} = $reported_tag;
+ if ( !$skipmetadata ) {
+ my $summary =
+ BuildSummary( $authrecord, $authid, $authtypecode );
+ my $query_auth_tag =
+"SELECT auth_tag_to_report FROM auth_types WHERE authtypecode=?";
+ my $sth = $dbh->prepare($query_auth_tag);
+ $sth->execute($authtypecode);
+ my $auth_tag_to_report = $sth->fetchrow;
+ my $reported_tag;
+ my $mainentry = $authrecord->field($auth_tag_to_report);
+ if ($mainentry) {
+
+ foreach ( $mainentry->subfields() ) {
+ $reported_tag .= '$' . $_->[0] . $_->[1];
+ }
+ }
+ $newline{summary} = $summary;
+ $newline{even} = $counter % 2;
+ $newline{reported_tag} = $reported_tag;
+ }
$counter++;
push @finalresult, \%newline;
}## while counter
- ###
- for (my $z=0; $z<@finalresult; $z++){
- my $count=CountUsage($finalresult[$z]{authid});
- $finalresult[$z]{used}=$count;
- }# all $z's
-
+ ###
+ if (! $skipmetadata) {
+ for (my $z=0; $z<@finalresult; $z++){
+ my $count=CountUsage($finalresult[$z]{authid});
+ $finalresult[$z]{used}=$count;
+ }# all $z's
+ }
+
}## if nbresult
NOLUCK:
- # $oAResult->destroy();
+ $oAResult->destroy();
# $oAuth[0]->destroy();
return (\@finalresult, $nbresults);
}
-sub AUTHhtml2marc {
- my ($rtags,$rsubfields,$rvalues,%indicators) = @_;
- my $dbh=C4::Context->dbh;
- my $prevtag = -1;
- my $record = MARC::Record->new();
-#---- TODO : the leader is missing
-
-# my %subfieldlist=();
- my $prevvalue; # if tag <10
- my $field; # if tag >=10
- for (my $i=0; $i< @$rtags; $i++) {
- # rebuild MARC::Record
- if (@$rtags[$i] ne $prevtag) {
- if ($prevtag < 10) {
- if ($prevvalue) {
- $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
- }
- } else {
- if ($field) {
- $record->add_fields($field);
- }
- }
- $indicators{@$rtags[$i]}.=' ';
- if (@$rtags[$i] <10) {
- $prevvalue= @$rvalues[$i];
- undef $field;
- } else {
- undef $prevvalue;
- $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
- }
- $prevtag = @$rtags[$i];
- } else {
- if (@$rtags[$i] <10) {
- $prevvalue=@$rvalues[$i];
- } else {
- if (length(@$rvalues[$i])>0) {
- $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
- }
- }
- $prevtag= @$rtags[$i];
- }
- }
- # the last has not been included inside the loop... do it now !
- $record->add_fields($field) if $field;
- return $record;
-}
-
=head2 FindDuplicateAuthority
$record= &FindDuplicateAuthority( $record, $authtypecode)
$resultstring =~ s/\n/<br>/g;
$summary = $resultstring;
} else {
- my $heading;
- my $altheading;
- my $seealso;
- my $broaderterms;
- my $narrowerterms;
- my $see;
- my $seeheading;
- my $notes;
+ my $heading = '';
+ my $altheading = '';
+ my $seealso = '';
+ my $broaderterms = '';
+ my $narrowerterms = '';
+ my $see = '';
+ my $seeheading = '';
+ my $notes = '';
my @fields = $record->fields();
if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
# construct UNIMARC summary, that is quite different from MARC21 one
my $auth_type_code = @_ ? shift : '';
my ($tag, $subfield) = GetAuthMARCFromKohaField('auth_header.authtypecode', $auth_type_code);
- if (defined $tag and defined $subfield and $tag != 0 and $subfield != 0) {
+ if (defined $tag and defined $subfield and $tag != 0 and $subfield ne '' and $subfield ne ' ') {
return ($tag, $subfield);
} else {
if (C4::Context->preference('marcflavour') eq "MARC21") {
use C4::Log; # logaction
use C4::ClassSource;
use C4::Charset;
+use C4::Linker;
use vars qw($VERSION @ISA @EXPORT);
# To link headings in a bib record
# to authority records.
push @EXPORT, qw(
+ &BiblioAutoLink
&LinkBibHeadingsToAuthorities
);
return;
}
+
+=head2 BiblioAutoLink
+
+ my $headings_linked = BiblioAutoLink($record, $frameworkcode)
+
+Automatically links headings in a bib record to authorities.
+
+=cut
+
+sub BiblioAutoLink {
+ my $record = shift;
+ my $frameworkcode = shift;
+ my ( $num_headings_changed, %results );
+
+ my $linker_module =
+ "C4::Linker::" . ( C4::Context->preference("LinkerModule") || 'Default' );
+ eval { eval "require $linker_module"; };
+ if ($@) {
+ $linker_module = 'C4::Linker::Default';
+ eval "require $linker_module";
+ }
+ if ($@) {
+ return 0, 0;
+ }
+
+ my $linker = $linker_module->new(
+ { 'options' => C4::Context->preference("LinkerOptions") } );
+ my ( $headings_changed, undef ) =
+ LinkBibHeadingsToAuthorities( $linker, $record, $frameworkcode, C4::Context->preference("CatalogModuleRelink") || '' );
+ # By default we probably don't want to relink things when cataloging
+ return $headings_changed;
+}
+
=head2 LinkBibHeadingsToAuthorities
- my $headings_linked = LinkBibHeadingsToAuthorities($marc);
+ my $num_headings_changed, %results = LinkBibHeadingsToAuthorities($linker, $marc, $frameworkcode, [$allowrelink]);
Links bib headings to authority records by checking
each authority-controlled field in the C<MARC::Record>
and setting the linking subfield $9 to the ID of that
authority record.
-If no matching authority exists, or if multiple
-authorities match, no $9 will be added, and any
-existing one inthe field will be deleted.
+If $allowrelink is false, existing authids will never be
+replaced, regardless of the values of LinkerKeepStale and
+LinkerRelink.
Returns the number of heading links changed in the
MARC record.
=cut
sub LinkBibHeadingsToAuthorities {
+ my $linker = shift;
+ my $bib = shift;
+ my $frameworkcode = shift;
+ my $allowrelink = shift;
+ my %results;
require C4::Heading;
- my $bib = shift;
+ require C4::AuthoritiesMarc;
+ $allowrelink = 1 unless defined $allowrelink;
my $num_headings_changed = 0;
foreach my $field ( $bib->fields() ) {
- my $heading = C4::Heading->new_from_bib_field($field);
+ my $heading = C4::Heading->new_from_bib_field( $field, $frameworkcode );
next unless defined $heading;
# check existing $9
my $current_link = $field->subfield('9');
- # look for matching authorities
- my $authorities = $heading->authorities();
+ if ( defined $current_link && (!$allowrelink || !C4::Context->preference('LinkerRelink')) )
+ {
+ $results{'linked'}->{ $heading->display_form() }++;
+ next;
+ }
- # want only one exact match
- if ( $#{$authorities} == 0 ) {
- my $authority = MARC::Record->new_from_usmarc( $authorities->[0] );
- my $authid = $authority->field('001')->data();
- next if defined $current_link and $current_link eq $authid;
+ my ( $authid, $fuzzy ) = $linker->get_link($heading);
+ if ($authid) {
+ $results{ $fuzzy ? 'fuzzy' : 'linked' }
+ ->{ $heading->display_form() }++;
+ next if defined $current_link and $current_link == $authid;
$field->delete_subfield( code => '9' ) if defined $current_link;
$field->add_subfields( '9', $authid );
$num_headings_changed++;
- } else {
- if ( defined $current_link ) {
+ }
+ else {
+ if ( defined $current_link
+ && (!$allowrelink || C4::Context->preference('LinkerKeepStale')) )
+ {
+ $results{'fuzzy'}->{ $heading->display_form() }++;
+ }
+ elsif ( C4::Context->preference('AutoCreateAuthorities') ) {
+ my $authtypedata =
+ C4::AuthoritiesMarc::GetAuthType( $heading->auth_type() );
+ my $marcrecordauth = MARC::Record->new();
+ if ( C4::Context->preference('marcflavour') eq 'MARC21' ) {
+ $marcrecordauth->leader(' nz a22 o 4500');
+ SetMarcUnicodeFlag( $marcrecordauth, 'MARC21' );
+ }
+ my $authfield =
+ MARC::Field->new( $authtypedata->{auth_tag_to_report},
+ '', '', "a" => "" . $field->subfield('a') );
+ map {
+ $authfield->add_subfields( $_->[0] => $_->[1] )
+ if ( $_->[0] =~ /[A-z]/ && $_->[0] ne "a" )
+ } $field->subfields();
+ $marcrecordauth->insert_fields_ordered($authfield);
+
+# bug 2317: ensure new authority knows it's using UTF-8; currently
+# only need to do this for MARC21, as MARC::Record->as_xml_record() handles
+# automatically for UNIMARC (by not transcoding)
+# FIXME: AddAuthority() instead should simply explicitly require that the MARC::Record
+# use UTF-8, but as of 2008-08-05, did not want to introduce that kind
+# of change to a core API just before the 3.0 release.
+
+ if ( C4::Context->preference('marcflavour') eq 'MARC21' ) {
+ $marcrecordauth->insert_fields_ordered(
+ MARC::Field->new(
+ '667', '', '',
+ 'a' => "Machine generated authority record."
+ )
+ );
+ my $cite =
+ $bib->author() . ", "
+ . $bib->title_proper() . ", "
+ . $bib->publication_date() . " ";
+ $cite =~ s/^[\s\,]*//;
+ $cite =~ s/[\s\,]*$//;
+ $cite =
+ "Work cat.: ("
+ . C4::Context->preference('MARCOrgCode') . ")"
+ . $bib->subfield( '999', 'c' ) . ": "
+ . $cite;
+ $marcrecordauth->insert_fields_ordered(
+ MARC::Field->new( '670', '', '', 'a' => $cite ) );
+ }
+
+ # warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
+
+ $authid =
+ C4::AuthoritiesMarc::AddAuthority( $marcrecordauth, '',
+ $heading->auth_type() );
+ $field->add_subfields( '9', $authid );
+ $num_headings_changed++;
+ $results{'added'}->{ $heading->display_form() }++;
+ }
+ elsif ( defined $current_link ) {
$field->delete_subfield( code => '9' );
$num_headings_changed++;
+ $results{'unlinked'}->{ $heading->display_form() }++;
+ }
+ else {
+ $results{'unlinked'}->{ $heading->display_form() }++;
}
}
}
- return $num_headings_changed;
+ return $num_headings_changed, \%results;
}
=head2 GetRecordValue
my ($hostbiblionumber,$hostitemnumber, $marcflavour) = @_;
$marcflavour ||="MARC21";
+ require C4::Items;
my $hostrecord = GetMarcBiblio($hostbiblionumber);
my $item = C4::Items::GetItem($hostitemnumber);
package C4::Heading;
# Copyright (C) 2008 LibLime
-#
+#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it under the
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
use strict;
-#use warnings; FIXME - Bug 2505
+use warnings;
use MARC::Record;
use MARC::Field;
use C4::Context;
-use C4::Heading::MARC21;
+use Module::Load;
use Carp;
our $VERSION = 3.00;
=head1 SYNOPSIS
use C4::Heading;
- my $heading = C4::Heading->new_from_bib_field($field);
+ my $heading = C4::Heading->new_from_bib_field($field, $frameworkcode);
my $thesaurus = $heading->thesaurus();
my $type = $heading->type();
- my $display_heading = $heading->display();
- my $search_string = $heading->search_string();
+ my $display_heading = $heading->display_form();
+ my $search_form = $heading->search_form();
=head1 DESCRIPTION
=head2 new_from_bib_field
- my $heading = C4::Heading->new_from_bib_field($field[, $marc_flavour]);
+ my $heading = C4::Heading->new_from_bib_field($field, $frameworkcode, [, $marc_flavour]);
Given a C<MARC::Field> object containing a heading from a
bib record, create a C<C4::Heading> object.
=cut
sub new_from_bib_field {
- my $class = shift;
- my $field = shift;
- my $marcflavour = @_ ? shift : C4::Context->preference('marcflavour');
+ my $class = shift;
+ my $field = shift;
+ my $frameworkcode = shift;
+ my $marcflavour = @_ ? shift : C4::Context->preference('marcflavour');
my $marc_handler = _marc_format_handler($marcflavour);
my $tag = $field->tag();
- return unless $marc_handler->valid_bib_heading_tag($tag);
+ return unless $marc_handler->valid_bib_heading_tag( $tag, $frameworkcode );
my $self = {};
-
- ($self->{'auth_type'}, $self->{'subject_added_entry'}, $self->{'series_added_entry'}, $self->{'main_entry'},
- $self->{'thesaurus'}, $self->{'search_form'}, $self->{'display_form'}) =
- $marc_handler->parse_heading($field);
+
+ $self->{'field'} = $field;
+ (
+ $self->{'auth_type'}, $self->{'thesaurus'},
+ $self->{'search_form'}, $self->{'display_form'},
+ $self->{'match_type'}
+ ) = $marc_handler->parse_heading($field);
bless $self, $class;
return $self;
}
+=head2 auth_type
+
+ my $auth_type = $heading->auth_type();
+
+Return the auth_type of the heading.
+
+=cut
+
+sub auth_type {
+ my $self = shift;
+ return $self->{'auth_type'};
+}
+
+=head2 field
+
+ my $field = $heading->field();
+
+Return the MARC::Field the heading is based on.
+
+=cut
+
+sub field {
+ my $self = shift;
+ return $self->{'field'};
+}
+
=head2 display_form
my $display = $heading->display_form();
return $self->{'display_form'};
}
+=head2 search_form
+
+ my $search_form = $heading->search_form();
+
+Return the "canonical" search form of the heading.
+
+=cut
+
+sub search_form {
+ my $self = shift;
+ return $self->{'search_form'};
+}
+
=head2 authorities
- my $authorities = $heading->authorities;
+ my $authorities = $heading->authorities([$skipmetadata]);
Return a list of authority records for this
-heading.
+heading. If passed a true value for $skipmetadata,
+SearchAuthorities will return only authids.
=cut
sub authorities {
- my $self = shift;
- my $query = qq(Match-heading,do-not-truncate,ext="$self->{'search_form'}");
- $query .= $self->_query_limiters();
- require C4::Search;
- my ($error, $results, $total_hits) = C4::Search::SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
- if (defined $error) {
- carp "Error:$error from search $query";
- }
+ my $self = shift;
+ my $skipmetadata = shift;
+ my ( $results, $total ) = _search( $self, 'match-heading', $skipmetadata );
return $results;
}
sub preferred_authorities {
my $self = shift;
- my $query = "Match-heading-see-from,do-not-truncate,ext='$self->{'search_form'}'";
- $query .= $self->_query_limiters();
- require C4::Search;
- my ($error, $results, $total_hits) = C4::Search::SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
- if (defined $error) {
- carp "Error:$error from search $query";
- }
+ my $skipmetadata = shift || undef;
+ my ( $results, $total ) = _search( 'see-from', $skipmetadata );
return $results;
}
=head1 INTERNAL METHODS
-=head2 _query_limiters
+=head2 _search
=cut
-sub _query_limiters {
- my $self = shift;
-
- my $limiters = " AND at='$self->{'auth_type'}'";
- if ($self->{'subject_added_entry'}) {
- $limiters .= " AND Heading-use-subject-added-entry=a"; # FIXME -- is this properly in C4::Heading::MARC21?
- $limiters .= " AND Subject-heading-thesaurus=$self->{'thesaurus'}";
- }
- if ($self->{'series_added_entry'}) {
- $limiters .= " AND Heading-use-series-added-entry=a"; # FIXME -- is this properly in C4::Heading::MARC21?
- }
- if (not $self->{'subject_added_entry'} and not $self->{'series_added_entry'}) {
- $limiters .= " AND Heading-use-main-or-added-entry=a" # FIXME -- is this properly in C4::Heading::MARC21?
+sub _search {
+ my $self = shift;
+ my $index = shift || undef;
+ my $skipmetadata = shift || undef;
+ my @marclist;
+ my @and_or;
+ my @excluding = [];
+ my @operator;
+ my @value;
+
+ if ($index) {
+ push @marclist, $index;
+ push @and_or, 'and';
+ push @operator, $self->{'match_type'};
+ push @value, $self->{'search_form'};
}
- return $limiters;
+
+ # if ($self->{'thesaurus'}) {
+ # push @marclist, 'thesaurus';
+ # push @and_or, 'and';
+ # push @excluding, '';
+ # push @operator, 'is';
+ # push @value, $self->{'thesaurus'};
+ # }
+ require C4::AuthoritiesMarc;
+ return C4::AuthoritiesMarc::SearchAuthorities(
+ \@marclist, \@and_or, \@excluding, \@operator,
+ \@value, 0, 20, $self->{'auth_type'},
+ '', $skipmetadata
+ );
}
=head1 INTERNAL FUNCTIONS
=cut
sub _marc_format_handler {
- my $marcflavour = shift;
-
- if ($marcflavour eq 'UNIMARC') {
- return C4::Heading::UNIMARC->new();
- } else {
- return C4::Heading::MARC21->new();
- }
-
+ my $marcflavour = uc shift;
+ $marcflavour = 'MARC21' if ( $marcflavour eq 'NORMARC' );
+ my $pname = "C4::Heading::$marcflavour";
+ load $pname;
+ return $pname->new();
}
=head1 AUTHOR
package C4::Heading::MARC21;
# Copyright (C) 2008 LibLime
-#
+#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it under the
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
use strict;
-#use warnings; FIXME - Bug 2505
+use warnings;
use MARC::Record;
use MARC::Field;
=cut
my $bib_heading_fields = {
- '100' => { auth_type => 'PERSO_NAME', subfields => 'abcdefghjklmnopqrst', main_entry => 1 },
- '110' => { auth_type => 'CORPO_NAME', subfields => 'abcdefghklmnoprst', main_entry => 1 },
- '111' => { auth_type => 'MEETI_NAME', subfields => 'acdefghjklnpqst', main_entry => 1 },
- '130' => { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprst', main_entry => 1 },
+ '100' => {
+ auth_type => 'PERSO_NAME',
+ subfields => 'abcdfghjklmnopqrst',
+ main_entry => 1
+ },
+ '110' => {
+ auth_type => 'CORPO_NAME',
+ subfields => 'abcdfghklmnoprst',
+ main_entry => 1
+ },
+ '111' => {
+ auth_type => 'MEETI_NAME',
+ subfields => 'acdfghjklnpqst',
+ main_entry => 1
+ },
+ '130' => {
+ auth_type => 'UNIF_TITLE',
+ subfields => 'adfghklmnoprst',
+ main_entry => 1
+ },
'440' => { auth_type => 'UNIF_TITLE', subfields => 'anp', series => 1 },
- '600' => { auth_type => 'PERSO_NAME', subfields => 'abcdefghjklmnopqrstvxyz', subject => 1 },
- '610' => { auth_type => 'CORPO_NAME', subfields => 'abcdefghklmnoprstvxyz', subject => 1 },
- '611' => { auth_type => 'MEETI_NAME', subfields => 'acdefghjklnpqstvxyz', subject => 1 },
- '630' => { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprstvxyz', subject => 1 },
- '648' => { auth_type => 'CHRON_TERM', subfields => 'avxyz', subject => 1 },
+ '600' => {
+ auth_type => 'PERSO_NAME',
+ subfields => 'abcdfghjklmnopqrstvxyz',
+ subject => 1
+ },
+ '610' => {
+ auth_type => 'CORPO_NAME',
+ subfields => 'abcdfghklmnoprstvxyz',
+ subject => 1
+ },
+ '611' => {
+ auth_type => 'MEETI_NAME',
+ subfields => 'acdfghjklnpqstvxyz',
+ subject => 1
+ },
+ '630' => {
+ auth_type => 'UNIF_TITLE',
+ subfields => 'adfghklmnoprstvxyz',
+ subject => 1
+ },
+ '648' => { auth_type => 'CHRON_TERM', subfields => 'avxyz', subject => 1 },
'650' => { auth_type => 'TOPIC_TERM', subfields => 'abvxyz', subject => 1 },
- '651' => { auth_type => 'GEOGR_NAME', subfields => 'avxyz', subject => 1 },
- '655' => { auth_type => 'GENRE/FORM', subfields => 'avxyz', subject => 1 },
- '700' => { auth_type => 'PERSO_NAME', subfields => 'abcdefghjklmnopqrst' },
- '710' => { auth_type => 'CORPO_NAME', subfields => 'abcdefghklmnoprst' },
- '711' => { auth_type => 'MEETI_NAME', subfields => 'acdefghjklnpqst' },
+ '651' => { auth_type => 'GEOGR_NAME', subfields => 'avxyz', subject => 1 },
+ '655' => { auth_type => 'GENRE/FORM', subfields => 'avxyz', subject => 1 },
+ '700' => { auth_type => 'PERSO_NAME', subfields => 'abcdfghjklmnopqrst' },
+ '710' => { auth_type => 'CORPO_NAME', subfields => 'abcdfghklmnoprst' },
+ '711' => { auth_type => 'MEETI_NAME', subfields => 'acdfghjklnpqst' },
'730' => { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprst' },
- '800' => { auth_type => 'PERSO_NAME', subfields => 'abcdefghjklmnopqrst', series => 1 },
- '810' => { auth_type => 'CORPO_NAME', subfields => 'abcdefghklmnoprst', series => 1 },
- '811' => { auth_type => 'MEETI_NAME', subfields => 'acdefghjklnpqst', series => 1 },
- '830' => { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprst', series => 1 },
+ '800' => {
+ auth_type => 'PERSO_NAME',
+ subfields => 'abcdfghjklmnopqrst',
+ series => 1
+ },
+ '810' => {
+ auth_type => 'CORPO_NAME',
+ subfields => 'abcdfghklmnoprst',
+ series => 1
+ },
+ '811' =>
+ { auth_type => 'MEETI_NAME', subfields => 'acdfghjklnpqst', series => 1 },
+ '830' =>
+ { auth_type => 'UNIF_TITLE', subfields => 'adfghklmnoprst', series => 1 },
};
=head2 subdivisions
=cut
sub valid_bib_heading_tag {
- my $self = shift;
- my $tag = shift;
+ my $self = shift;
+ my $tag = shift;
+ my $frameworkcode = shift;
- if (exists $bib_heading_fields->{$tag}) {
- return 1
- } else {
+ if ( exists $bib_heading_fields->{$tag} ) {
+ return 1;
+ }
+ else {
return 0;
}
=cut
sub parse_heading {
- my $self = shift;
+ my $self = shift;
my $field = shift;
- my $tag = $field->tag;
+ my $tag = $field->tag;
my $field_info = $bib_heading_fields->{$tag};
my $auth_type = $field_info->{'auth_type'};
- my $subject = $field_info->{'subject'} ? 1 : 0;
- my $series = $field_info->{'series'} ? 1 : 0;
- my $main_entry = $field_info->{'main_entry'} ? 1 : 0;
- my $thesaurus = $subject ? _get_subject_thesaurus($field) : "lcsh"; # use 'lcsh' for names, UT, etc.
- my $search_heading = _get_search_heading($field, $field_info->{'subfields'});
- my $display_heading = _get_display_heading($field, $field_info->{'subfields'});
-
- return ($auth_type, $subject, $series, $main_entry, $thesaurus, $search_heading, $display_heading);
+ my $thesaurus =
+ $tag =~ m/6../
+ ? _get_subject_thesaurus($field)
+ : "lcsh"; # use 'lcsh' for names, UT, etc.
+ my $search_heading =
+ _get_search_heading( $field, $field_info->{'subfields'} );
+ my $display_heading =
+ _get_display_heading( $field, $field_info->{'subfields'} );
+
+ return ( $auth_type, $thesaurus, $search_heading, $display_heading,
+ 'exact' );
}
=head1 INTERNAL FUNCTIONS
sub _get_subject_thesaurus {
my $field = shift;
- my $ind2 = $field->indicator(2);
+ my $ind2 = $field->indicator(2);
my $thesaurus = "notdefined";
- if ($ind2 eq '0') {
+ if ( $ind2 eq '0' ) {
$thesaurus = "lcsh";
- } elsif ($ind2 eq '1') {
+ }
+ elsif ( $ind2 eq '1' ) {
$thesaurus = "lcac";
- } elsif ($ind2 eq '2') {
+ }
+ elsif ( $ind2 eq '2' ) {
$thesaurus = "mesh";
- } elsif ($ind2 eq '3') {
+ }
+ elsif ( $ind2 eq '3' ) {
$thesaurus = "nal";
- } elsif ($ind2 eq '4') {
+ }
+ elsif ( $ind2 eq '4' ) {
$thesaurus = "notspecified";
- } elsif ($ind2 eq '5') {
+ }
+ elsif ( $ind2 eq '5' ) {
$thesaurus = "cash";
- } elsif ($ind2 eq '6') {
+ }
+ elsif ( $ind2 eq '6' ) {
$thesaurus = "rvm";
- } elsif ($ind2 eq '7') {
+ }
+ elsif ( $ind2 eq '7' ) {
my $sf2 = $field->subfield('2');
$thesaurus = $sf2 if defined($sf2);
}
=cut
sub _get_search_heading {
- my $field = shift;
+ my $field = shift;
my $subfields = shift;
- my $heading = "";
+ my $heading = "";
my @subfields = $field->subfields();
- my $first = 1;
- for (my $i = 0; $i <= $#subfields; $i++) {
- my $code = $subfields[$i]->[0];
+ my $first = 1;
+ for ( my $i = 0 ; $i <= $#subfields ; $i++ ) {
+ my $code = $subfields[$i]->[0];
my $code_re = quotemeta $code;
- my $value = $subfields[$i]->[1];
+ my $value = $subfields[$i]->[1];
+ $value =~ s/[-,.:=;!%\/]$//;
next unless $subfields =~ qr/$code_re/;
if ($first) {
- $first = 0;
+ $first = 0;
$heading = $value;
- } else {
- if (exists $subdivisions{$code}) {
+ }
+ else {
+ if ( exists $subdivisions{$code} ) {
$heading .= " $subdivisions{$code} $value";
- } else {
+ }
+ else {
$heading .= " $value";
}
}
=cut
sub _get_display_heading {
- my $field = shift;
+ my $field = shift;
my $subfields = shift;
- my $heading = "";
+ my $heading = "";
my @subfields = $field->subfields();
- my $first = 1;
- for (my $i = 0; $i <= $#subfields; $i++) {
- my $code = $subfields[$i]->[0];
+ my $first = 1;
+ for ( my $i = 0 ; $i <= $#subfields ; $i++ ) {
+ my $code = $subfields[$i]->[0];
my $code_re = quotemeta $code;
- my $value = $subfields[$i]->[1];
+ my $value = $subfields[$i]->[1];
next unless $subfields =~ qr/$code_re/;
if ($first) {
- $first = 0;
+ $first = 0;
$heading = $value;
- } else {
- if (exists $subdivisions{$code}) {
+ }
+ else {
+ if ( exists $subdivisions{$code} ) {
$heading .= "--$value";
- } else {
+ }
+ else {
$heading .= " $value";
}
}
return $heading;
}
+# Additional limiters that we aren't using:
+# if ($self->{'subject_added_entry'}) {
+# $limiters .= " AND Heading-use-subject-added-entry=a";
+# }
+# if ($self->{'series_added_entry'}) {
+# $limiters .= " AND Heading-use-series-added-entry=a";
+# }
+# if (not $self->{'subject_added_entry'} and not $self->{'series_added_entry'}) {
+# $limiters .= " AND Heading-use-main-or-added-entry=a"
+# }
+
=head1 AUTHOR
Koha Development Team <http://koha-community.org/>
--- /dev/null
+package C4::Heading::UNIMARC;
+
+# Copyright (C) 2011 C & P Bibliography Services
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use 5.010;
+use strict;
+use warnings;
+use MARC::Record;
+use MARC::Field;
+use C4::Context;
+
+our $VERSION = 3.00;
+
+=head1 NAME
+
+C4::Heading::UNIMARC
+
+=head1 SYNOPSIS
+
+use C4::Heading::UNIMARC;
+
+=head1 DESCRIPTION
+
+This is an internal helper class used by
+C<C4::Heading> to parse headings data from
+UNIMARC records. Object of this type
+do not carry data, instead, they only
+dispatch functions.
+
+=head1 DATA STRUCTURES
+
+FIXME - this should be moved to a configuration file.
+
+=head2 subdivisions
+
+=cut
+
+my %subdivisions = (
+ 'j' => 'formsubdiv',
+ 'x' => 'generalsubdiv',
+ 'y' => 'chronologicalsubdiv',
+ 'z' => 'geographicsubdiv',
+);
+
+my $bib_heading_fields;
+
+BEGIN {
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare(
+ "SELECT tagfield, authtypecode
+ FROM marc_subfield_structure
+ WHERE frameworkcode = '' AND authtypecode <> ''"
+ );
+ $sth->execute();
+ $bib_heading_fields = {};
+ while ( my ( $tag, $auth_type ) = $sth->fetchrow ) {
+ $bib_heading_fields->{$tag} = {
+ auth_type => $auth_type,
+ subfields => 'abcdefghjklmnopqrstvxyz',
+ };
+ }
+}
+
+=head1 METHODS
+
+=head2 new
+
+ my $marc_handler = C4::Heading::UNIMARC->new();
+
+=cut
+
+sub new {
+ my $class = shift;
+ return bless {}, $class;
+}
+
+=head2 valid_bib_heading_tag
+
+=cut
+
+sub valid_bib_heading_tag {
+ my ( $self, $tag ) = @_;
+ return $bib_heading_fields->{$tag};
+}
+
+=head2 parse_heading
+
+=cut
+
+sub parse_heading {
+ my ( $self, $field ) = @_;
+
+ my $tag = $field->tag;
+ my $field_info = $bib_heading_fields->{$tag};
+ my $auth_type = $field_info->{'auth_type'};
+ my $search_heading =
+ _get_search_heading( $field, $field_info->{'subfields'} );
+ my $display_heading =
+ _get_display_heading( $field, $field_info->{'subfields'} );
+
+ return ( $auth_type, undef, $search_heading, $display_heading, 'exact' );
+}
+
+=head1 INTERNAL FUNCTIONS
+
+=head2 _get_subject_thesaurus
+
+=cut
+
+sub _get_subject_thesaurus {
+ my $field = shift;
+
+ my $thesaurus = "notdefined";
+ my $sf2 = $field->subfield('2');
+ $thesaurus = $sf2 if defined($sf2);
+
+ return $thesaurus;
+}
+
+=head2 _get_search_heading
+
+=cut
+
+sub _get_search_heading {
+ my $field = shift;
+ my $subfields = shift;
+
+ my $heading = "";
+ my @subfields = $field->subfields();
+ my $first = 1;
+ for ( my $i = 0 ; $i <= $#subfields ; $i++ ) {
+ my $code = $subfields[$i]->[0];
+ my $code_re = quotemeta $code;
+ my $value = $subfields[$i]->[1];
+ $value =~ s/[-,.:=;!%\/]*$//;
+ next unless $subfields =~ qr/$code_re/;
+ if ($first) {
+ $first = 0;
+ $heading = $value;
+ }
+ else {
+ $heading .= " $value";
+ }
+ }
+
+ # remove characters that are part of CCL syntax
+ $heading =~ s/[)(=]//g;
+
+ return $heading;
+}
+
+=head2 _get_display_heading
+
+=cut
+
+sub _get_display_heading {
+ my $field = shift;
+ my $subfields = shift;
+
+ my $heading = "";
+ my @subfields = $field->subfields();
+ my $first = 1;
+ for ( my $i = 0 ; $i <= $#subfields ; $i++ ) {
+ my $code = $subfields[$i]->[0];
+ my $code_re = quotemeta $code;
+ my $value = $subfields[$i]->[1];
+ next unless $subfields =~ qr/$code_re/;
+ if ($first) {
+ $first = 0;
+ $heading = $value;
+ }
+ else {
+ if ( exists $subdivisions{$code} ) {
+ $heading .= "--$value";
+ }
+ else {
+ $heading .= " $value";
+ }
+ }
+ }
+ return $heading;
+}
+
+=head1 AUTHOR
+
+Koha Development Team <http://koha-community.org/>
+
+Jared Camins-Esakov <jcamins@cpbibliography.com>
+
+=cut
+
+1;
--- /dev/null
+package C4::Linker;
+
+# Copyright 2011 C & P Bibliography Services
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+=head1 NAME
+
+C4::Linker - Base class for linking authorities to bibliographic records
+
+=head1 SYNOPSIS
+
+ use C4::Linker (%params );
+
+=head1 DESCRIPTION
+
+Base class for C4::Linker::X. Subclasses need to provide the following methods
+
+B<get_link ($field)> - return the authid for the authority that should be
+linked to the provided MARC::Field object, and a boolean to indicate whether
+the match is "fuzzy" (the semantics of "fuzzy" are up to the individual plugin).
+In order to handle authority limits, get_link should always end with:
+ return $self->SUPER::_handle_auth_limit($authid), $fuzzy;
+
+B<flip_heading ($field)> - return a MARC::Field object with the heading flipped
+to the preferred form.
+
+=head1 FUNCTIONS
+
+=cut
+
+use strict;
+use warnings;
+use Carp;
+use C4::Context;
+
+use base qw(Class::Accessor);
+
+__PACKAGE__->mk_accessors(qw( ));
+
+sub new {
+ my $class = shift;
+ my $param = shift;
+
+ my $self = {};
+
+ while ( my ( $key, $value ) = each %$param ) {
+ if ( $key eq 'auth_limit' && $value ) {
+ my $dbh = C4::Context->dbh;
+ my $sql =
+ "SELECT authid FROM auth_header WHERE $value ORDER BY authid ASC";
+ my $sth = $dbh->prepare($sql);
+ $sth->execute();
+ while ( my ($authid) = $sth->fetchrow_array() ) {
+ push @{ $self->{'auths_to_link'} }, $authid;
+ }
+ }
+ elsif ( $key eq 'options' && $value ) {
+ foreach my $opt ( split( /\|/, $value ) ) {
+ $self->{$opt} = 1;
+ }
+ }
+ elsif ($value) {
+ $self->{$key} = $value;
+ }
+ }
+
+ bless $self, $class;
+ return $self;
+}
+
+=head2 _handle_auth_limit
+
+ return $self->SUPER::_handle_auth_limit($authid), $fuzzy;
+
+=back
+
+Function to be called by subclasses to handle authority record limits.
+
+=cut
+
+sub _handle_auth_limit {
+ my $self = shift;
+ my $authid = shift;
+
+ if ( defined $self->{'auths_to_link'} && defined $authid && !grep { $_ == $authid }
+ @{ $self->{'auths_to_link'} } )
+ {
+ undef $authid;
+ }
+ return $authid;
+}
+
+=head2 EXPORT
+
+None by default.
+
+=head1 SEE ALSO
+
+C4::Linker::Default
+
+=head1 AUTHOR
+
+Jared Camins-Esakov, C & P Bibliography Services, E<lt>jcamins@cpbibliography.comE<gt>
+
+=cut
+
+1;
+
+__END__
--- /dev/null
+package C4::Linker::Default;
+
+# Copyright 2011 C & P Bibliography Services
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+use Carp;
+use MARC::Field;
+use C4::Heading;
+
+use base qw(C4::Linker);
+
+sub get_link {
+ my $self = shift;
+ my $heading = shift;
+ my $behavior = shift || 'default';
+ my $search_form = $heading->search_form();
+ my $authid;
+ my $fuzzy = 0;
+
+ if ( $self->{'cache'}->{$search_form}->{'cached'} ) {
+ $authid = $self->{'cache'}->{$search_form}->{'authid'};
+ $fuzzy = $self->{'cache'}->{$search_form}->{'fuzzy'};
+ }
+ else {
+
+ # look for matching authorities
+ my $authorities = $heading->authorities(1); # $skipmetadata = true
+
+ if ( $behavior eq 'default' && $#{$authorities} == 0 ) {
+ $authid = $authorities->[0]->{'authid'};
+ }
+ elsif ( $behavior eq 'first' && $#{$authorities} >= 0 ) {
+ $authid = $authorities->[0]->{'authid'};
+ $fuzzy = $#{$authorities} > 0;
+ }
+ elsif ( $behavior eq 'last' && $#{$authorities} >= 0 ) {
+ $authid = $authorities->[ $#{$authorities} ]->{'authid'};
+ $fuzzy = $#{$authorities} > 0;
+ }
+
+ if ( !defined $authid && $self->{'broader_headings'} ) {
+ my $field = $heading->field();
+ my @subfields = $field->subfields();
+ if ( scalar @subfields > 1 ) {
+ pop @subfields;
+ $field->replace_with(
+ MARC::Field->new(
+ $field->tag,
+ $field->indicator(1),
+ $field->indicator(2),
+ map { $_[0] => $_[1] } @subfields
+ )
+ );
+ ( $authid, $fuzzy ) =
+ $self->get_link( C4::Heading->new_from_bib_field($field),
+ $behavior );
+ }
+ }
+
+ $self->{'cache'}->{$search_form}->{'cached'} = 1;
+ $self->{'cache'}->{$search_form}->{'authid'} = $authid;
+ $self->{'cache'}->{$search_form}->{'fuzzy'} = $fuzzy;
+ }
+ return $self->SUPER::_handle_auth_limit($authid), $fuzzy;
+}
+
+sub flip_heading {
+ my $self = shift;
+ my $heading = shift;
+
+ # TODO: implement
+}
+
+1;
+__END__
+
+=head1 NAME
+
+C4::Linker::Default - match only if there is a single matching auth
+
+=cut
--- /dev/null
+package C4::Linker::FirstMatch;
+
+# Copyright 2011 C & P Bibliography Services
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+use Carp;
+use C4::Heading;
+use C4::Linker::Default; # Use Default for flipping
+
+use base qw(C4::Linker);
+
+sub new {
+ my $class = shift;
+ my $param = shift;
+
+ my $self = $class->SUPER::new($param);
+ $self->{'default_linker'} = C4::Linker::Default->new($param);
+ bless $self, $class;
+ return $self;
+}
+
+sub get_link {
+ my $self = shift;
+ my $heading = shift;
+ return $self->{'default_linker'}->get_link( $heading, 'first' );
+}
+
+sub flip_heading {
+ my $self = shift;
+ my $heading = shift;
+
+ return $self->{'default_linker'}->flip($heading);
+}
+
+1;
+__END__
+
+=head1 NAME
+
+C4::Linker::FirstMatch - match against the first authority record
+
+=cut
--- /dev/null
+package C4::Linker::LastMatch;
+
+# Copyright 2011 C & P Bibliography Services
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+use Carp;
+use C4::Heading;
+use C4::Linker::Default; # Use Default for flipping
+
+use base qw(C4::Linker);
+
+sub new {
+ my $class = shift;
+ my $param = shift;
+
+ my $self = $class->SUPER::new($param);
+ $self->{'default_linker'} = C4::Linker::Default->new($param);
+ bless $self, $class;
+ return $self;
+}
+
+sub get_link {
+ my $self = shift;
+ my $heading = shift;
+ return $self->{'default_linker'}->get_link( $heading, 'last' );
+}
+
+sub flip_heading {
+ my $self = shift;
+ my $heading = shift;
+
+ return $self->{'default_linker'}->flip($heading);
+}
+
+1;
+__END__
+
+=head1 NAME
+
+C4::Linker::LastMatch - match against the last authority record
+
+=cut
&NZgetRecords
&AddSearchHistory
&GetDistinctValues
- &BiblioAddAuthorities
&enabled_staff_search_views
);
-#FIXME: i had to add BiblioAddAuthorities here because in Biblios.pm it caused circular dependencies (C4::Search uses C4::Biblio, and BiblioAddAuthorities uses SimpleSearch from C4::Search)
# make all your functions, whether exported or not;
return $array;
}
-=head2 BiblioAddAuthorities
-
-( $countlinked, $countcreated ) = BiblioAddAuthorities($record, $frameworkcode);
-
-this function finds the authorities linked to the biblio
- * search in the authority DB for the same authid (in $9 of the biblio)
- * search in the authority DB for the same 001 (in $3 of the biblio in UNIMARC)
- * search in the authority DB for the same values (exactly) (in all subfields of the biblio)
-OR adds a new authority record
-
-=over 2
-
-=item C<input arg:>
-
- * $record is the MARC record in question (marc blob)
- * $frameworkcode is the bibliographic framework to use (if it is "" it uses the default framework)
-
-=item C<Output arg:>
-
- * $countlinked is the number of authorities records that are linked to this authority
- * $countcreated
-
-=item C<BUGS>
- * I had to add this to Search.pm (instead of the logical Biblio.pm) because of a circular dependency (this sub uses SimpleSearch, and Search.pm uses Biblio.pm)
-
-=back
-
-=cut
-
-
-sub BiblioAddAuthorities{
- my ( $record, $frameworkcode ) = @_;
- my $dbh=C4::Context->dbh;
- my $query=$dbh->prepare(qq|
-SELECT authtypecode,tagfield
-FROM marc_subfield_structure
-WHERE frameworkcode=?
-AND (authtypecode IS NOT NULL AND authtypecode<>\"\")|);
-# SELECT authtypecode,tagfield
-# FROM marc_subfield_structure
-# WHERE frameworkcode=?
-# AND (authtypecode IS NOT NULL OR authtypecode<>\"\")|);
- $query->execute($frameworkcode);
- my ($countcreated,$countlinked);
- while (my $data=$query->fetchrow_hashref){
- foreach my $field ($record->field($data->{tagfield})){
- next if ($field->subfield('3')||$field->subfield('9'));
- # No authorities id in the tag.
- # Search if there is any authorities to link to.
- my $query='at='.$data->{authtypecode}.' ';
- map {$query.= ' and he,ext="'.$_->[1].'"' if ($_->[0]=~/[A-z]/)} $field->subfields();
- my ($error, $results, $total_hits)=SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
- # there is only 1 result
- if ( $error ) {
- warn "BIBLIOADDSAUTHORITIES: $error";
- return (0,0) ;
- }
- if ( @{$results} == 1 ) {
- my $marcrecord = MARC::File::USMARC::decode($results->[0]);
- $field->add_subfields('9'=>$marcrecord->field('001')->data);
- $countlinked++;
- } elsif ( @{$results} > 1 ) {
- #More than One result
- #This can comes out of a lack of a subfield.
-# my $marcrecord = MARC::File::USMARC::decode($results->[0]);
-# $record->field($data->{tagfield})->add_subfields('9'=>$marcrecord->field('001')->data);
- $countlinked++;
- } else {
- #There are no results, build authority record, add it to Authorities, get authid and add it to 9
- ###NOTICE : This is only valid if a subfield is linked to one and only one authtypecode
- ###NOTICE : This can be a problem. We should also look into other types and rejected forms.
- my $authtypedata=C4::AuthoritiesMarc::GetAuthType($data->{authtypecode});
- next unless $authtypedata;
- my $marcrecordauth=MARC::Record->new();
- my $authfield=MARC::Field->new($authtypedata->{auth_tag_to_report},'','',"a"=>"".$field->subfield('a'));
- map { $authfield->add_subfields($_->[0]=>$_->[1]) if ($_->[0]=~/[A-z]/ && $_->[0] ne "a" )} $field->subfields();
- $marcrecordauth->insert_fields_ordered($authfield);
-
- # bug 2317: ensure new authority knows it's using UTF-8; currently
- # only need to do this for MARC21, as MARC::Record->as_xml_record() handles
- # automatically for UNIMARC (by not transcoding)
- # FIXME: AddAuthority() instead should simply explicitly require that the MARC::Record
- # use UTF-8, but as of 2008-08-05, did not want to introduce that kind
- # of change to a core API just before the 3.0 release.
- if (C4::Context->preference('marcflavour') eq 'MARC21') {
- SetMarcUnicodeFlag($marcrecordauth, 'MARC21');
- }
-
-# warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
-
- my $authid=AddAuthority($marcrecordauth,'',$data->{authtypecode});
- $countcreated++;
- $field->add_subfields('9'=>$authid);
- }
- }
- }
- return ($countlinked,$countcreated);
-}
-
=head2 GetDistinctValues($field);
C<$field> is a reference to the fields array
use C4::Output;
use C4::ImportBatch;
use C4::Matcher;
-use C4::Search qw/FindDuplicate BiblioAddAuthorities/;
+use C4::Search qw/FindDuplicate/;
use C4::Acquisition;
use C4::Biblio;
use C4::Items;
SetImportRecordStatus( $biblio->{'import_record_id'}, 'imported' );
# 2nd add authorities if applicable
if (C4::Context->preference("BiblioAddsAuthorities")){
- my ($countlinked,$countcreated)=BiblioAddAuthorities($marcrecord, $cgiparams->{'frameworkcode'});
+ my $headings_linked =BiblioAutoLink($marcrecord, $cgiparams->{'frameworkcode'});
}
} else {
SetImportRecordStatus( $biblio->{'import_record_id'}, 'imported' );
use C4::Koha;
use C4::Branch; # GetBranches
use C4::Members;
-use C4::Search qw/FindDuplicate BiblioAddAuthorities/;
+use C4::Search qw/FindDuplicate/;
#needed for z3950 import:
use C4::ImportBatch qw/GetImportRecordMarc SetImportRecordStatus/;
}
#from this point: add a new record
if (C4::Context->preference("BiblioAddsAuthorities")){
- my ($countlinked,$countcreated)=BiblioAddAuthorities($marcrecord, $params->{'frameworkcode'});
+ my $headings_linked=BiblioAutoLink($marcrecord, $params->{'frameworkcode'});
}
my $bibitemnum;
$params->{'frameworkcode'} or $params->{'frameworkcode'} = "";
my @and_or = $query->param('and_or');
my @excluding = $query->param('excluding');
my @operator = $query->param('operator');
- my @value = ($query->param('value_mainstr')||undef, $query->param('value_main')||undef, $query->param('value_any')||undef);
+ my @value = ($query->param('value_mainstr')||undef, $query->param('value_main')||undef, $query->param('value_any')||undef, $query->param('value_match')||undef);
my $orderby = $query->param('orderby');
$resultsperpage = $query->param('resultsperpage');
push @field_data, { term => "value_mainstr", val => $query->param('value_mainstr') || "" };
push @field_data, { term => "value_main", val => $query->param('value_main') || "" };
push @field_data, { term => "value_any", val => $query->param('value_any') || ""};
+ push @field_data, { term => "value_match", val => $query->param('value_match') || ""};
my @numbers = ();
value_mainstr => $query->param('value_mainstr') || "",
value_main => $query->param('value_main') || "",
value_any => $query->param('value_any') || "",
+ value_match => $query->param('value_match') || "",
);
} else {
( $template, $loggedinuser, $cookie ) = get_template_and_user(
value_mainstr => $query->param('value_mainstr') || "",
value_main => $query->param('value_main') || "",
value_any => $query->param('value_any') || "",
+ value_match => $query->param('value_match') || "",
tagid => $tagid,
index => $index,
authtypesloop => \@authtypesloop,
authtypecode => $authtypecode,
- value_mainstr => $query->param('value_mainstr') || "",
- value_main => $query->param('value_main') || "",
- value_any => $query->param('value_any') || "",
);
# Print the page
$template->param( BIG_LOOP => \@BIG_LOOP );
}
-#
-# sub that tries to find authorities linked to the biblio
-# the sub :
-# - search in the authority DB for the same authid (in $9 of the biblio)
-# - search in the authority DB for the same 001 (in $3 of the biblio in UNIMARC)
-# - search in the authority DB for the same values (exactly) (in all subfields of the biblio)
-# if the authority is found, the biblio is modified accordingly to be connected to the authority.
-# if the authority is not found, it's added, and the biblio is then modified to be connected to the authority.
-#
-
-sub BiblioAddAuthorities{
- my ( $record, $frameworkcode ) = @_;
- my $dbh=C4::Context->dbh;
- my $query=$dbh->prepare(qq|
-SELECT authtypecode,tagfield
-FROM marc_subfield_structure
-WHERE frameworkcode=?
-AND (authtypecode IS NOT NULL AND authtypecode<>\"\")|);
-# SELECT authtypecode,tagfield
-# FROM marc_subfield_structure
-# WHERE frameworkcode=?
-# AND (authtypecode IS NOT NULL OR authtypecode<>\"\")|);
- $query->execute($frameworkcode);
- my ($countcreated,$countlinked);
- while (my $data=$query->fetchrow_hashref){
- foreach my $field ($record->field($data->{tagfield})){
- next if ($field->subfield('3') || $field->subfield('9'));
- # No authorities id in the tag.
- # Search if there is any authorities to link to.
- my $query='at='.$data->{authtypecode}.' ';
- map {$query.= ' and he,ext="'.$_->[1].'"' if ($_->[0]=~/[A-z]/)} $field->subfields();
- my ($error, $results, $total_hits)=SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
- # there is only 1 result
- if ( $error ) {
- warn "BIBLIOADDSAUTHORITIES: $error";
- return (0,0) ;
- }
- if ( @{$results} == 1) {
- my $marcrecord = MARC::File::USMARC::decode($results->[0]);
- $field->add_subfields('9'=>$marcrecord->field('001')->data);
- $countlinked++;
- } elsif (@{$results} > 1) {
- #More than One result
- #This can comes out of a lack of a subfield.
-# my $marcrecord = MARC::File::USMARC::decode($results->[0]);
-# $record->field($data->{tagfield})->add_subfields('9'=>$marcrecord->field('001')->data);
- $countlinked++;
- } else {
- #There are no results, build authority record, add it to Authorities, get authid and add it to 9
- ###NOTICE : This is only valid if a subfield is linked to one and only one authtypecode
- ###NOTICE : This can be a problem. We should also look into other types and rejected forms.
- my $authtypedata=GetAuthType($data->{authtypecode});
- next unless $authtypedata;
- my $marcrecordauth=MARC::Record->new();
- if (C4::Context->preference('marcflavour') eq 'MARC21') {
- $marcrecordauth->leader(' nz a22 o 4500');
- SetMarcUnicodeFlag($marcrecordauth, 'MARC21');
- }
- my $authfield=MARC::Field->new($authtypedata->{auth_tag_to_report},'','',"a"=>"".$field->subfield('a'));
- map { $authfield->add_subfields($_->[0]=>$_->[1]) if ($_->[0]=~/[A-z]/ && $_->[0] ne "a" )} $field->subfields();
- $marcrecordauth->insert_fields_ordered($authfield);
-
- # bug 2317: ensure new authority knows it's using UTF-8; currently
- # only need to do this for MARC21, as MARC::Record->as_xml_record() handles
- # automatically for UNIMARC (by not transcoding)
- # FIXME: AddAuthority() instead should simply explicitly require that the MARC::Record
- # use UTF-8, but as of 2008-08-05, did not want to introduce that kind
- # of change to a core API just before the 3.0 release.
-
- if (C4::Context->preference('marcflavour') eq 'MARC21') {
- $marcrecordauth->insert_fields_ordered(MARC::Field->new('667','','','a'=>"Machine generated authority record."));
- my $cite = $record->author() . ", " . $record->title_proper() . ", " . $record->publication_date() . " ";
- $cite =~ s/^[\s\,]*//;
- $cite =~ s/[\s\,]*$//;
- $cite = "Work cat.: (" . C4::Context->preference('MARCOrgCode') . ")". $record->subfield('999','c') . ": " . $cite;
- $marcrecordauth->insert_fields_ordered(MARC::Field->new('670','','','a'=>$cite));
- }
-
-# warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
-
- my $authid=AddAuthority($marcrecordauth,'',$data->{authtypecode});
- $countcreated++;
- $field->add_subfields('9'=>$authid);
- }
- }
- }
- return ($countlinked,$countcreated);
-}
-
# ========================
# MAIN
#=========================
my $oldbibnum;
my $oldbibitemnum;
if (C4::Context->preference("BiblioAddsAuthorities")){
- my ($countlinked,$countcreated)=BiblioAddAuthorities($record,$frameworkcode);
+ my ($countlinked,$countcreated)=BiblioAutoLink($record,$frameworkcode);
}
if ( $is_a_modif ) {
ModBiblioframework( $biblionumber, $frameworkcode );
att 8808 Subdivision-see-from
att 8809 Match-heading-see-from
att 8810 Match-subdivision-see-from
+att 8900 Match
# General Subdivision (defined in att 47)
att 9023 General-subdivision
<kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="100" subfields="abcdefghjklmnopqrstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-from:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="400" subfields="abcdefghjklmnopqrstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-also-from:p</kohaidx:target_index>
<kohaidx:target_index>See-also-from:s</kohaidx:target_index>
</kohaidx:index_heading>
+ <kohaidx:index_match_heading tag="500" subfields="abcdefghjklmnopqrstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
+ </kohaidx:index_match_heading>
<!-- Corporate name headings -->
<kohaidx:index_subfields tag="110" subfields="abcdefghklmnoprstvxyz">
<kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="110" subfields="abcdefghklmnoprstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-from:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="410" subfields="abcdefghklmnoprstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-also-from:p</kohaidx:target_index>
<kohaidx:target_index>See-also-from:s</kohaidx:target_index>
</kohaidx:index_heading>
+ <kohaidx:index_match_heading tag="510" subfields="abcdefghklmnoprstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
+ </kohaidx:index_match_heading>
<!-- Meeting name -->
<kohaidx:index_subfields tag="111" subfields="acdefghjklnpqstvxyz">
<kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="111" subfields="acdefghjklnpqstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-from:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="411" subfields="acdefghjklnpqstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-also-from:p</kohaidx:target_index>
<kohaidx:target_index>See-also-from:s</kohaidx:target_index>
</kohaidx:index_heading>
+ <kohaidx:index_match_heading tag="511" subfields="acdefghjklnpqstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
+ </kohaidx:index_match_heading>
<!-- Uniform title -->
<kohaidx:index_subfields tag="130" subfields="adfghklmnoprstvxyz">
<kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="130" subfields="adfghklmnoprstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-from:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="430" subfields="adfghklmnoprstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-also-from:p</kohaidx:target_index>
<kohaidx:target_index>See-also-from:s</kohaidx:target_index>
</kohaidx:index_heading>
+ <kohaidx:index_match_heading tag="530" subfields="adfghklmnoprstvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
+ </kohaidx:index_match_heading>
<!-- Chronological term -->
<kohaidx:index_subfields tag="148" subfields="avxyz">
<kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="148" subfields="avxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-from:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="448" subfields="avxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-also-from:p</kohaidx:target_index>
<kohaidx:target_index>See-also-from:s</kohaidx:target_index>
</kohaidx:index_heading>
+ <kohaidx:index_match_heading tag="548" subfields="avxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
+ </kohaidx:index_match_heading>
<!-- Topical term -->
<kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="150" subfields="abvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-from:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="450" subfields="abvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-also-from:p</kohaidx:target_index>
<kohaidx:target_index>See-also-from:s</kohaidx:target_index>
</kohaidx:index_heading>
+ <kohaidx:index_match_heading tag="550" subfields="abvxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
+ </kohaidx:index_match_heading>
<!-- Geographic name -->
<kohaidx:index_subfields tag="151" subfields="avxyz">
<kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="151" subfields="avxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-from:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="451" subfields="avxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-also-from:p</kohaidx:target_index>
<kohaidx:target_index>See-also-from:s</kohaidx:target_index>
</kohaidx:index_heading>
+ <kohaidx:index_match_heading tag="551" subfields="avxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
+ </kohaidx:index_match_heading>
<!-- Genre/form term -->
<kohaidx:index_subfields tag="155" subfields="avxyz">
<kohaidx:target_index>Heading-Main:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="155" subfields="avxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-from:s</kohaidx:target_index>
</kohaidx:index_heading>
<kohaidx:index_match_heading tag="455" subfields="avxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:p</kohaidx:target_index>
<kohaidx:target_index>Match-heading-see-from:s</kohaidx:target_index>
</kohaidx:index_match_heading>
<kohaidx:target_index>See-also-from:p</kohaidx:target_index>
<kohaidx:target_index>See-also-from:s</kohaidx:target_index>
</kohaidx:index_heading>
+ <kohaidx:index_match_heading tag="555" subfields="avxyz" subdivisions="vxyz">
+ <kohaidx:target_index>Match:w</kohaidx:target_index>
+ <kohaidx:target_index>Match:p</kohaidx:target_index>
+ </kohaidx:index_match_heading>
<!-- General subdivision -->
<kohaidx:index_heading tag="180" subfields="vxyz" subdivisions="vxyz">
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='100']">
- <z:index name="Match-heading:p Match-heading:s">
+ <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match-heading:p Match-heading:s">
+ <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='400']">
- <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
+ <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
+ <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
+ </xslo:if>
+ </xslo:for-each>
+ </xslo:variable>
+ <xslo:value-of select="normalize-space($raw_heading)"/>
+ </z:index>
+ </xslo:template>
+ <xslo:template mode="index_match_heading" match="marc:datafield[@tag='500']">
+ <z:index name="Match:w Match:p">
+ <xslo:variable name="raw_heading">
+ <xslo:for-each select="marc:subfield">
+ <xslo:if test="contains('abcdefghjklmnopqrstvxyz', @code)" name="Match:w Match:p">
+ <xslo:if test="position() > 1">
+ <xslo:choose>
+ <xslo:when test="contains('vxyz', @code)">
+ <xslo:choose>
+ <xslo:when test="@code = $general_subdivision_subfield">
+ <xslo:text> generalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $form_subdivision_subfield">
+ <xslo:text> formsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $chronological_subdivision_subfield">
+ <xslo:text> chronologicalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $geographic_subdivision_subfield">
+ <xslo:text> geographicsubdiv </xslo:text>
+ </xslo:when>
+ </xslo:choose>
+ </xslo:when>
+ <xslo:otherwise>
+ <xslo:value-of select="substring(' ', 1, 1)"/>
+ </xslo:otherwise>
+ </xslo:choose>
+ </xslo:if>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='110']">
- <z:index name="Match-heading:p Match-heading:s">
+ <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match-heading:p Match-heading:s">
+ <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='410']">
- <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
+ <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
+ <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
+ </xslo:if>
+ </xslo:for-each>
+ </xslo:variable>
+ <xslo:value-of select="normalize-space($raw_heading)"/>
+ </z:index>
+ </xslo:template>
+ <xslo:template mode="index_match_heading" match="marc:datafield[@tag='510']">
+ <z:index name="Match:w Match:p">
+ <xslo:variable name="raw_heading">
+ <xslo:for-each select="marc:subfield">
+ <xslo:if test="contains('abcdefghklmnoprstvxyz', @code)" name="Match:w Match:p">
+ <xslo:if test="position() > 1">
+ <xslo:choose>
+ <xslo:when test="contains('vxyz', @code)">
+ <xslo:choose>
+ <xslo:when test="@code = $general_subdivision_subfield">
+ <xslo:text> generalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $form_subdivision_subfield">
+ <xslo:text> formsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $chronological_subdivision_subfield">
+ <xslo:text> chronologicalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $geographic_subdivision_subfield">
+ <xslo:text> geographicsubdiv </xslo:text>
+ </xslo:when>
+ </xslo:choose>
+ </xslo:when>
+ <xslo:otherwise>
+ <xslo:value-of select="substring(' ', 1, 1)"/>
+ </xslo:otherwise>
+ </xslo:choose>
+ </xslo:if>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='111']">
- <z:index name="Match-heading:p Match-heading:s">
+ <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match-heading:p Match-heading:s">
+ <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='411']">
- <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
+ <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
+ <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
+ </xslo:if>
+ </xslo:for-each>
+ </xslo:variable>
+ <xslo:value-of select="normalize-space($raw_heading)"/>
+ </z:index>
+ </xslo:template>
+ <xslo:template mode="index_match_heading" match="marc:datafield[@tag='511']">
+ <z:index name="Match:w Match:p">
+ <xslo:variable name="raw_heading">
+ <xslo:for-each select="marc:subfield">
+ <xslo:if test="contains('acdefghjklnpqstvxyz', @code)" name="Match:w Match:p">
+ <xslo:if test="position() > 1">
+ <xslo:choose>
+ <xslo:when test="contains('vxyz', @code)">
+ <xslo:choose>
+ <xslo:when test="@code = $general_subdivision_subfield">
+ <xslo:text> generalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $form_subdivision_subfield">
+ <xslo:text> formsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $chronological_subdivision_subfield">
+ <xslo:text> chronologicalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $geographic_subdivision_subfield">
+ <xslo:text> geographicsubdiv </xslo:text>
+ </xslo:when>
+ </xslo:choose>
+ </xslo:when>
+ <xslo:otherwise>
+ <xslo:value-of select="substring(' ', 1, 1)"/>
+ </xslo:otherwise>
+ </xslo:choose>
+ </xslo:if>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='130']">
- <z:index name="Match-heading:p Match-heading:s">
+ <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match-heading:p Match-heading:s">
+ <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='430']">
- <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
+ <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
+ <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
+ </xslo:if>
+ </xslo:for-each>
+ </xslo:variable>
+ <xslo:value-of select="normalize-space($raw_heading)"/>
+ </z:index>
+ </xslo:template>
+ <xslo:template mode="index_match_heading" match="marc:datafield[@tag='530']">
+ <z:index name="Match:w Match:p">
+ <xslo:variable name="raw_heading">
+ <xslo:for-each select="marc:subfield">
+ <xslo:if test="contains('adfghklmnoprstvxyz', @code)" name="Match:w Match:p">
+ <xslo:if test="position() > 1">
+ <xslo:choose>
+ <xslo:when test="contains('vxyz', @code)">
+ <xslo:choose>
+ <xslo:when test="@code = $general_subdivision_subfield">
+ <xslo:text> generalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $form_subdivision_subfield">
+ <xslo:text> formsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $chronological_subdivision_subfield">
+ <xslo:text> chronologicalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $geographic_subdivision_subfield">
+ <xslo:text> geographicsubdiv </xslo:text>
+ </xslo:when>
+ </xslo:choose>
+ </xslo:when>
+ <xslo:otherwise>
+ <xslo:value-of select="substring(' ', 1, 1)"/>
+ </xslo:otherwise>
+ </xslo:choose>
+ </xslo:if>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='148']">
- <z:index name="Match-heading:p Match-heading:s">
+ <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('avxyz', @code)" name="Match-heading:p Match-heading:s">
+ <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='448']">
- <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
+ <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('avxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
+ <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
+ </xslo:if>
+ </xslo:for-each>
+ </xslo:variable>
+ <xslo:value-of select="normalize-space($raw_heading)"/>
+ </z:index>
+ </xslo:template>
+ <xslo:template mode="index_match_heading" match="marc:datafield[@tag='548']">
+ <z:index name="Match:w Match:p">
+ <xslo:variable name="raw_heading">
+ <xslo:for-each select="marc:subfield">
+ <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p">
+ <xslo:if test="position() > 1">
+ <xslo:choose>
+ <xslo:when test="contains('vxyz', @code)">
+ <xslo:choose>
+ <xslo:when test="@code = $general_subdivision_subfield">
+ <xslo:text> generalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $form_subdivision_subfield">
+ <xslo:text> formsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $chronological_subdivision_subfield">
+ <xslo:text> chronologicalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $geographic_subdivision_subfield">
+ <xslo:text> geographicsubdiv </xslo:text>
+ </xslo:when>
+ </xslo:choose>
+ </xslo:when>
+ <xslo:otherwise>
+ <xslo:value-of select="substring(' ', 1, 1)"/>
+ </xslo:otherwise>
+ </xslo:choose>
+ </xslo:if>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='150']">
- <z:index name="Match-heading:p Match-heading:s">
+ <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('abvxyz', @code)" name="Match-heading:p Match-heading:s">
+ <xslo:if test="contains('abvxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='450']">
- <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
+ <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('abvxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
+ <xslo:if test="contains('abvxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
+ </xslo:if>
+ </xslo:for-each>
+ </xslo:variable>
+ <xslo:value-of select="normalize-space($raw_heading)"/>
+ </z:index>
+ </xslo:template>
+ <xslo:template mode="index_match_heading" match="marc:datafield[@tag='550']">
+ <z:index name="Match:w Match:p">
+ <xslo:variable name="raw_heading">
+ <xslo:for-each select="marc:subfield">
+ <xslo:if test="contains('abvxyz', @code)" name="Match:w Match:p">
+ <xslo:if test="position() > 1">
+ <xslo:choose>
+ <xslo:when test="contains('vxyz', @code)">
+ <xslo:choose>
+ <xslo:when test="@code = $general_subdivision_subfield">
+ <xslo:text> generalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $form_subdivision_subfield">
+ <xslo:text> formsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $chronological_subdivision_subfield">
+ <xslo:text> chronologicalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $geographic_subdivision_subfield">
+ <xslo:text> geographicsubdiv </xslo:text>
+ </xslo:when>
+ </xslo:choose>
+ </xslo:when>
+ <xslo:otherwise>
+ <xslo:value-of select="substring(' ', 1, 1)"/>
+ </xslo:otherwise>
+ </xslo:choose>
+ </xslo:if>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='151']">
- <z:index name="Match-heading:p Match-heading:s">
+ <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('avxyz', @code)" name="Match-heading:p Match-heading:s">
+ <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='451']">
- <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
+ <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('avxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
+ <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
+ </xslo:if>
+ </xslo:for-each>
+ </xslo:variable>
+ <xslo:value-of select="normalize-space($raw_heading)"/>
+ </z:index>
+ </xslo:template>
+ <xslo:template mode="index_match_heading" match="marc:datafield[@tag='551']">
+ <z:index name="Match:w Match:p">
+ <xslo:variable name="raw_heading">
+ <xslo:for-each select="marc:subfield">
+ <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p">
+ <xslo:if test="position() > 1">
+ <xslo:choose>
+ <xslo:when test="contains('vxyz', @code)">
+ <xslo:choose>
+ <xslo:when test="@code = $general_subdivision_subfield">
+ <xslo:text> generalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $form_subdivision_subfield">
+ <xslo:text> formsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $chronological_subdivision_subfield">
+ <xslo:text> chronologicalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $geographic_subdivision_subfield">
+ <xslo:text> geographicsubdiv </xslo:text>
+ </xslo:when>
+ </xslo:choose>
+ </xslo:when>
+ <xslo:otherwise>
+ <xslo:value-of select="substring(' ', 1, 1)"/>
+ </xslo:otherwise>
+ </xslo:choose>
+ </xslo:if>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='155']">
- <z:index name="Match-heading:p Match-heading:s">
+ <z:index name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('avxyz', @code)" name="Match-heading:p Match-heading:s">
+ <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading:p Match-heading:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</z:index>
</xslo:template>
<xslo:template mode="index_match_heading" match="marc:datafield[@tag='455']">
- <z:index name="Match-heading-see-from:p Match-heading-see-from:s">
+ <z:index name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:variable name="raw_heading">
<xslo:for-each select="marc:subfield">
- <xslo:if test="contains('avxyz', @code)" name="Match-heading-see-from:p Match-heading-see-from:s">
+ <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p Match-heading-see-from:p Match-heading-see-from:s">
<xslo:if test="position() > 1">
<xslo:choose>
<xslo:when test="contains('vxyz', @code)">
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
+ </xslo:if>
+ </xslo:for-each>
+ </xslo:variable>
+ <xslo:value-of select="normalize-space($raw_heading)"/>
+ </z:index>
+ </xslo:template>
+ <xslo:template mode="index_match_heading" match="marc:datafield[@tag='555']">
+ <z:index name="Match:w Match:p">
+ <xslo:variable name="raw_heading">
+ <xslo:for-each select="marc:subfield">
+ <xslo:if test="contains('avxyz', @code)" name="Match:w Match:p">
+ <xslo:if test="position() > 1">
+ <xslo:choose>
+ <xslo:when test="contains('vxyz', @code)">
+ <xslo:choose>
+ <xslo:when test="@code = $general_subdivision_subfield">
+ <xslo:text> generalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $form_subdivision_subfield">
+ <xslo:text> formsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $chronological_subdivision_subfield">
+ <xslo:text> chronologicalsubdiv </xslo:text>
+ </xslo:when>
+ <xslo:when test="@code = $geographic_subdivision_subfield">
+ <xslo:text> geographicsubdiv </xslo:text>
+ </xslo:when>
+ </xslo:choose>
+ </xslo:when>
+ <xslo:otherwise>
+ <xslo:value-of select="substring(' ', 1, 1)"/>
+ </xslo:otherwise>
+ </xslo:choose>
+ </xslo:if>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
<xslo:value-of select="."/>
</z:index>
</xslo:template>
+ <xslo:template name="chopPunctuation">
+ <xslo:param name="chopString"/>
+ <xslo:variable name="length" select="string-length($chopString)"/>
+ <xslo:choose>
+ <xslo:when test="$length=0"/>
+ <xslo:when test="contains('-,.:=;!%/', substring($chopString,$length,1))">
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
+ </xslo:call-template>
+ </xslo:when>
+ <xslo:when test="not($chopString)"/>
+ <xslo:otherwise>
+ <xslo:value-of select="$chopString"/>
+ </xslo:otherwise>
+ </xslo:choose>
+ <xslo:text/>
+ </xslo:template>
</xslo:stylesheet>
<xslo:value-of select="."/>
</z:index>
</xslo:template>
+ <xslo:template name="chopPunctuation">
+ <xslo:param name="chopString"/>
+ <xslo:variable name="length" select="string-length($chopString)"/>
+ <xslo:choose>
+ <xslo:when test="$length=0"/>
+ <xslo:when test="contains('-,.:=;!%/', substring($chopString,$length,1))">
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString" select="substring($chopString,1,$length - 1)"/>
+ </xslo:call-template>
+ </xslo:when>
+ <xslo:when test="not($chopString)"/>
+ <xslo:otherwise><xslo:value-of select="$chopString"/></xslo:otherwise>
+ </xslo:choose>
+ <xslo:text> </xslo:text>
+ </xslo:template>
</xslo:stylesheet>
</xsl:template>
</xslo:otherwise>
</xslo:choose>
</xslo:if>
- <xslo:value-of select="."/>
+ <xslo:call-template name="chopPunctuation">
+ <xslo:with-param name="chopString">
+ <xslo:value-of select="."/>
+ </xslo:with-param>
+ </xslo:call-template>
</xslo:if>
</xslo:for-each>
</xslo:variable>
melm 152$b authtype:w,authtype:p
# Personal Name
-melm 200$a Personal-name-heading:w,Personal-name-heading:p,Personal-name-heading:s,Personal-name:w,Personal-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 200 Personal-name:w,Personal-name:p,Heading:w,Heading:p
-melm 400 Personal-name-see:w,Personal-name-see:p,See:w,See:p
-melm 500 Personal-name-see-also:w,Personal-name-see-also:p,See-also:w,See-also:p
-melm 700$a Personal-name-parallel:w,Personal-name-parallel:p,Parallel:w,Parallel:p
+melm 200$a Personal-name-heading:w,Personal-name-heading:p,Personal-name-heading:s,Personal-name:w,Personal-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 200 Personal-name:w,Personal-name:p,Heading:w,Heading:p,Match:w,Match:p
+melm 400 Personal-name-see:w,Personal-name-see:p,See:w,See:p,Match:w,Match:p
+melm 500 Personal-name-see-also:w,Personal-name-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 700$a Personal-name-parallel:w,Personal-name-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# Corporate Name
-melm 210$a Corporate-name-heading:w,Corporate-name-heading:p,Corporate-name-heading:s,Corporate-name:w,Corporate-name:p,Conference-name-heading:w,Conference-name-heading:p,Conference-name-heading:s,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 210 Corporate-name:w,Corporate-name:p,Conference-name:w,Conference-name:p,Heading:w,Heading:p
-melm 410 Corporate-name-see:w,Corporate-name-see:p,Conference-name-see:w,Conference-name-see:p,See:w,See:p
-melm 510 Corporate-name-see-also:w,Corporate-name-see-also:p,Conference-name-see-also:w,Conference-name-see-also:p,See-also:w,See-also:p
-melm 710 Corporate-name-parallel:w,Corporate-name-parallel:p,Parallel:w,Parallel:p
+melm 210$a Corporate-name-heading:w,Corporate-name-heading:p,Corporate-name-heading:s,Corporate-name:w,Corporate-name:p,Conference-name-heading:w,Conference-name-heading:p,Conference-name-heading:s,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 210 Corporate-name:w,Corporate-name:p,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Match:w,Match:p
+melm 410 Corporate-name-see:w,Corporate-name-see:p,Conference-name-see:w,Conference-name-see:p,See:w,See:p,Match:w,Match:p
+melm 510 Corporate-name-see-also:w,Corporate-name-see-also:p,Conference-name-see-also:w,Conference-name-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 710 Corporate-name-parallel:w,Corporate-name-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# Geographic & Geographic Name
-melm 215$a Name-geographic-heading:w,Name-geographic-heading:w,Name-geographic-heading:s,Name-geographic:w,Name-geographic:p,Term-geographic-heading:w,Term-geographic-heading:p,Term-geographic-heading:s,Term-geographic:w,Term-geographic:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 215 Name-geographic-heading:w,Name-geographic-heading:w,Name-geographic-heading:s,Name-geographic:w,Name-geographic:p,Term-geographic:w,Term-geographic:p,Term-geographic:s,Heading:w,Heading:p,Heading:s
-melm 415 Name-geographic-see:w,Name-geographic-see:p,Term-geographic-see:w,Term-geographic-see:p,Term-geographic-see:s,See:w,See:p,See:s
-melm 515 Name-geographic-see-also:w,Name-geographic-see-also:p,Term-geographic-see-also:w,Term-geographic-see-also:p,Term-geographic-see-also:s,See-also:w,See-also:p,See-also:s
-melm 715 Name-geographic-parallel:w,Name-geographic-parallel:p,Term-geographic-parallel:w,Term-geographic-parallel:p,Term-geographic-parallel:s,Parallel:w,Parallel:p,Parallel:s
+melm 215$a Name-geographic-heading:w,Name-geographic-heading:w,Name-geographic-heading:s,Name-geographic:w,Name-geographic:p,Term-geographic-heading:w,Term-geographic-heading:p,Term-geographic-heading:s,Term-geographic:w,Term-geographic:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 215 Name-geographic-heading:w,Name-geographic-heading:w,Name-geographic-heading:s,Name-geographic:w,Name-geographic:p,Term-geographic:w,Term-geographic:p,Term-geographic:s,Heading:w,Heading:p,Heading:s,Match:w,Match:p
+melm 415 Name-geographic-see:w,Name-geographic-see:p,Term-geographic-see:w,Term-geographic-see:p,Term-geographic-see:s,See:w,See:p,See:s,Match:w,Match:p
+melm 515 Name-geographic-see-also:w,Name-geographic-see-also:p,Term-geographic-see-also:w,Term-geographic-see-also:p,Term-geographic-see-also:s,See-also:w,See-also:p,See-also:s,Match:w,Match:p
+melm 715 Name-geographic-parallel:w,Name-geographic-parallel:p,Term-geographic-parallel:w,Term-geographic-parallel:p,Term-geographic-parallel:s,Parallel:w,Parallel:p,Parallel:s,Match:w,Match:p
# Trademark
-melm 216$a Trademark-heading:w,Trademark-heading:p,Trademark-heading:s,Trademark:w,Trademark:p,Conference-name-heading:w,Conference-name-heading:p,Conference-name-heading:s,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 216 Trademark:w,Trademark:p,Conference-name:w,Conference-name:p,Heading:w,Heading:p
-melm 416 Trademark-see:w,Trademark-see:p,Conference-name-see:w,Conference-name-see:p,See:w,See:p
-melm 516 Trademark-see-also:w,Trademark-see-also:p,Conference-name-see-also:w,Conference-name-see-also:p,See-also:w,See-also:p
-melm 716 Trademark-parallel:w,Trademark-parallel:p,Parallel:w,Parallel:p
+melm 216$a Trademark-heading:w,Trademark-heading:p,Trademark-heading:s,Trademark:w,Trademark:p,Conference-name-heading:w,Conference-name-heading:p,Conference-name-heading:s,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 216 Trademark:w,Trademark:p,Conference-name:w,Conference-name:p,Heading:w,Heading:p,Match:w,Match:p
+melm 416 Trademark-see:w,Trademark-see:p,Conference-name-see:w,Conference-name-see:p,See:w,See:p,Match:w,Match:p
+melm 516 Trademark-see-also:w,Trademark-see-also:p,Conference-name-see-also:w,Conference-name-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 716 Trademark-parallel:w,Trademark-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# Family Name
-melm 220$a Name-heading:w,Name-heading:p,Name-heading:s,Name:w,Name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 220 Name:w,Name:p,Name:s,Heading:w,Heading:p,Heading:s
-melm 420 Name-see:w,Name-see:p,Name-see:s,See:w,See:p,See:s
-melm 520 Name-see-also:w,Name-see-also:p,Name-see-also:s,See-also:w,See-also:p,See-also:s
-melm 720 Name-parallel:w,Name-parallel:p,Name-parallel:s,Parallel:w,Parallel:p,Parallel:s
+melm 220$a Name-heading:w,Name-heading:p,Name-heading:s,Name:w,Name:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 220 Name:w,Name:p,Name:s,Heading:w,Heading:p,Heading:s,Match:w,Match:p
+melm 420 Name-see:w,Name-see:p,Name-see:s,See:w,See:p,See:s,Match:w,Match:p
+melm 520 Name-see-also:w,Name-see-also:p,Name-see-also:s,See-also:w,See-also:p,See-also:s,Match:w,Match:p
+melm 720 Name-parallel:w,Name-parallel:p,Name-parallel:s,Parallel:w,Parallel:p,Parallel:s,Match:w,Match:p
# Uniform Title
-melm 230$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 230 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p
-melm 430 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p
-melm 530 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p
-melm 730$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p
+melm 230$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 230 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Match:w,Match:p
+melm 430 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p,Match:w,Match:p
+melm 530 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 730$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# Second area for uniform titles in UNIMARC?
-melm 235$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 235 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p
-melm 435 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p
-melm 535 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p
-melm 735$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p
+melm 235$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 235 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Match:w,Match:p
+melm 435 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p,Match:w,Match:p
+melm 535 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 735$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# Uniform Title
-melm 240$a Name-Title-heading:w,Name-Title-heading:p,Name-Title-heading:s,Name-Title:w,Name-Title:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 240 Name-Title:w,Name-Title:p,Heading:w,Heading:p
-melm 440 Name-Title-see:w,Name-Title-see:p,See:w,See:p
-melm 540 Name-Title-see-also:w,Name-Title-see-also:p,See-also:w,See-also:p
-melm 740$a Name-Title-parallel:w,Name-Title-parallel:p,Parallel:w,Parallel:p
+melm 240$a Name-Title-heading:w,Name-Title-heading:p,Name-Title-heading:s,Name-Title:w,Name-Title:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 240 Name-Title:w,Name-Title:p,Heading:w,Heading:p,Match:w,Match:p
+melm 440 Name-Title-see:w,Name-Title-see:p,See:w,See:p,Match:w,Match:p
+melm 540 Name-Title-see-also:w,Name-Title-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 740$a Name-Title-parallel:w,Name-Title-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# Second area for uniform titles in UNIMARC?
-melm 245$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 245 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p
-melm 445 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p
-melm 545 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p
-melm 745$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p
+melm 245$a Title-uniform-heading:w,Title-uniform-heading:p,Title-uniform-heading:s,Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 245 Title-uniform:w,Title-uniform:p,Heading:w,Heading:p,Match:w,Match:p
+melm 445 Title-uniform-see:w,Title-uniform-see:p,See:w,See:p,Match:w,Match:p
+melm 545 Title-uniform-see-also:w,Title-uniform-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 745$a Title-uniform-parallel:w,Title-uniform-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# Topical Term
-melm 250$a Subject-heading:w,Subject-heading:p,Subject-heading:s,Subject:w,Subject:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 250 Subject:w,Subject:p,Heading:w,Heading:p,Subject-heading:w,Subject-heading:p,Subject-heading:s
-melm 450 Subject-see:w,Subject-see:p,See:w,See:p
-melm 550 Subject-see-also:w,Subject-see-also:p,See-also:w,See-also:p
-melm 750$a Subject-parallel:w,Subject-parallel:p,Parallel:w,Parallel:p
+melm 250$a Subject-heading:w,Subject-heading:p,Subject-heading:s,Subject:w,Subject:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 250 Subject:w,Subject:p,Heading:w,Heading:p,Subject-heading:w,Subject-heading:p,Subject-heading:s,Match:w,Match:p
+melm 450 Subject-see:w,Subject-see:p,See:w,See:p,Match:w,Match:p
+melm 550 Subject-see-also:w,Subject-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 750$a Subject-parallel:w,Subject-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# Place Access
-melm 260$a Place-heading:w,Place-heading:p,Place-heading:s,Place:w,Place:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 260 Place:w,Place:p,Heading:w,Heading:p,Place-heading:w,Place-heading:p,Place-heading:s
-melm 460 Place-see:w,Place-see:p,See:w,See:p
-melm 560 Place-see-also:w,Place-see-also:p,See-also:w,See-also:p
-melm 760$a Place-parallel:w,Place-parallel:p,Parallel:w,Parallel:p
+melm 260$a Place-heading:w,Place-heading:p,Place-heading:s,Place:w,Place:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 260 Place:w,Place:p,Heading:w,Heading:p,Place-heading:w,Place-heading:p,Place-heading:s,Match:w,Match:p
+melm 460 Place-see:w,Place-see:p,See:w,See:p,Match:w,Match:p
+melm 560 Place-see-also:w,Place-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 760$a Place-parallel:w,Place-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# Form Genre
-melm 280$a Form-heading:w,Form-heading:p,Form-heading:s,Form:w,Form:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s
-melm 280 Form:w,Form:p,Heading:w,Heading:p,Form-heading:w,Form-heading:p,Form-heading:s
-melm 480 Form-see:w,Form-see:p,See:w,See:p
-melm 580 Form-see-also:w,Form-see-also:p,See-also:w,See-also:p
-melm 780$a Form-parallel:w,Form-parallel:p,Parallel:w,Parallel:p
+melm 280$a Form-heading:w,Form-heading:p,Form-heading:s,Form:w,Form:p,Heading:w,Heading:p,Heading:s,Heading-Main:w,Heading-Main:p,Heading-Main:s,Match:w,Match:p
+melm 280 Form:w,Form:p,Heading:w,Heading:p,Form-heading:w,Form-heading:p,Form-heading:s,Match:w,Match:p
+melm 480 Form-see:w,Form-see:p,See:w,See:p,Match:w,Match:p
+melm 580 Form-see-also:w,Form-see-also:p,See-also:w,See-also:p,Match:w,Match:p
+melm 780$a Form-parallel:w,Form-parallel:p,Parallel:w,Parallel:p,Match:w,Match:p
# NOTE: subdivisions management missing from Koha
--- /dev/null
+#! /usr/bin/perl
+use strict;
+use warnings;
+use C4::Context;
+my $dbh = C4::Context->dbh;
+$dbh->do(
+"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerModule','Default','Chooses which linker module to use (see documentation).','Default|FirstMatchLastMatch','Choice');"
+);
+$dbh->do(
+"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerOptions','','A pipe-separated list of options for the linker.','','free');"
+);
+$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');"
+);
+$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');"
+);
+$dbh->do(
+"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('AutoCreateAuthorities',0,'Automatically create authorities that do not exist when cataloging records.',NULL,'YesNo');"
+);
+print "Upgrade done (Configured bug 7284, improved authority matching)\n";
--- /dev/null
+#! /usr/bin/perl
+use strict;
+use warnings;
+use C4::Context;
+my $dbh = C4::Context->dbh;
+$dbh->do(
+"INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('CatalogModuleRelink',0,'If OFF the linker will never replace the authids that are set in the cataloging module.',NULL,'YesNo');"
+);
+print "Upgrade done (Configured bug 7284, added the )\n";
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('BorrowerRenewalPeriodBase', 'now', 'Set whether the borrower renewal date should be counted from the dateexpiry or from the current date ','dateexpiry|now','Choice');
INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES ('AllowItemsOnHoldCheckout',0,'Do not generate RESERVE_WAITING and RESERVED warning when checking out items reserved to someone else. This allows self checkouts for those items.','','YesNo');
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacExportOptions','bibtex|dc|marcxml|marc8|utf8|marcstd|mods|ris','Define export options available on OPAC detail page.','','free');
+INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('AutoCreateAuthorities',0,'Automatically create authorities that do not exist when cataloging records.',NULL,'YesNo');
+INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerModule','Default','Chooses which linker module to use (see documentation).','Default|FirstMatch|LastMatch','Choice');
+INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('LinkerOptions','','A pipe-separated list of options for the linker.','','free');
+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');
+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');
+INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('CatalogModuleRelink',0,'If OFF the linker will never replace the authids that are set in the cataloging module.',NULL,'YesNo');
</li>
<li>
<label for="marclist">Anywhere</label>
- <input type="hidden" name="marclist" value="" />
+ <input type="hidden" name="marclist" value="any" />
<input type="hidden" name="and_or" value="and" />
<input type="hidden" name="excluding" value="" />
<select name="operator" id="marclist">
</select>
<input type="text" name="value_any" value="[% value_any |html %]" />
</li>
+ <li>
+ <label for="marclist">Heading match</label>
+ <input type="hidden" name="marclist" value="match" />
+ <input type="hidden" name="and_or" value="and" />
+ <input type="hidden" name="excluding" value="" />
+ <select name="operator" id="marclist">
+ <option value="contains">contains</option>
+ <option value="start">starts with</option>
+ <option value="is">is exactly</option>
+ </select>
+ <input type="text" name="value_match" value="[% value_match |html %]" />
+ </li>
<li>
<label for="orderby">Sort by </label>
<select name="orderby" id="orderby">
Authorities:
- -
- - When editing records,
- - pref: BiblioAddsAuthorities
- default: no
- choices:
- yes: allow
- no: "don't allow"
- - them to automatically create new authority records if needed, rather than having to reference existing authorities.
- -
- - pref: dontmerge
- default: yes
- choices:
- yes: "Don't"
- no: Do
- - automatically update attached biblios when changing an authority record. If this is off, please ask your administrator to enable the merge_authority.pl cronjob.
- -
- - 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).
- - pref: MARCAuthorityControlField008
- default: "|| aca||aabn | a|a d"
- type: textarea
- class: code
- -
- - pref: UseAuthoritiesForTracings
- default: yes
- choices:
- yes: Use
- no: "Don't use"
- - authority record numbers instead of text strings for searches from subject tracings.
+ General:
+ -
+ - When editing records,
+ - pref: BiblioAddsAuthorities
+ default: no
+ choices:
+ yes: allow
+ no: "don't allow"
+ - them to automatically create new authority records if needed, rather than having to reference existing authorities.
+ -
+ - When editing records,
+ - pref: AutoCreateAuthorities
+ default: yes
+ choices:
+ yes: generate
+ no: "do not generate"
+ - authority records that are missing (BiblioAddsAuthorities must be set to "allow" for this to have any effect).
+ -
+ - pref: dontmerge
+ default: yes
+ choices:
+ yes: "Don't"
+ no: Do
+ - automatically update attached biblios when changing an authority record. If this is off, please ask your administrator to enable the merge_authority.pl cronjob.
+ -
+ - 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).
+ - pref: MARCAuthorityControlField008
+ default: "|| aca||aabn | a|a d"
+ type: textarea
+ class: code
+ -
+ - pref: UseAuthoritiesForTracings
+ default: yes
+ choices:
+ yes: Use
+ no: "Don't use"
+ - authority record numbers instead of text strings for searches from subject tracings.
+ Linker:
+ -
+ - Use the
+ - pref: LinkerModule
+ default: Default
+ choices:
+ Default: Default
+ FirstMatch: "First Match"
+ LastMatch: "Last Match"
+ - linker module for matching headings to authority records.
+ -
+ - Set the following options for the authority linker
+ - pref: LinkerOptions
+ class: multi
+ - (separate options with |)
+ -
+ - pref: LinkerRelink
+ default: yes
+ choices:
+ yes: Do
+ no: "Do not"
+ - relink headings that have previously been linked to authority records.
+ -
+ - pref: LinkerKeepStale
+ default: no
+ choices:
+ yes: Do
+ no: "Do not"
+ - keep existing links to authority records for headings where the linker is unable to find a match.
+ -
+ - pref: CatalogModuleRelink
+ default: no
+ choices:
+ yes: Do
+ no: "Do not"
+ - automatically relink headings that have previously been linked when saving records in the cataloging module.
use strict;
use warnings;
+
BEGIN {
+
# find Koha's Perl modules
# test carefully before changing this
use FindBin;
use C4::Context;
use C4::Biblio;
use Getopt::Long;
+use Pod::Usage;
+use Data::Dumper;
+use Time::HiRes qw/time/;
+use POSIX qw/strftime ceil/;
+
+sub usage {
+ pod2usage( -verbose => 2 );
+ exit;
+}
$| = 1;
# command-line parameters
-my $verbose = 0;
-my $test_only = 0;
-my $want_help = 0;
+my $verbose = 0;
+my $link_report = 0;
+my $test_only = 0;
+my $want_help = 0;
+my $auth_limit;
+my $bib_limit;
+my $commit = 100;
my $result = GetOptions(
- 'verbose' => \$verbose,
- 'test' => \$test_only,
- 'h|help' => \$want_help
+ 'v|verbose' => \$verbose,
+ 't|test' => \$test_only,
+ 'l|link-report' => \$link_report,
+ 'a|auth-limit=s' => \$auth_limit,
+ 'b|bib-limit=s' => \$bib_limit,
+ 'c|commit=i' => \$commit,
+ 'h|help' => \$want_help
);
-if (not $result or $want_help) {
- print_usage();
- exit 0;
+binmode( STDOUT, ":utf8" );
+
+if ( not $result or $want_help ) {
+ usage();
+}
+
+my $linker_module =
+ "C4::Linker::" . ( C4::Context->preference("LinkerModule") || 'Default' );
+eval { eval "require $linker_module"; };
+if ($@) {
+ $linker_module = 'C4::Linker::Default';
+ eval "require $linker_module";
}
+if ($@) {
+ die "Unable to load linker module. Aborting.";
+}
+
+my $linker = $linker_module->new(
+ {
+ 'auth_limit' => $auth_limit,
+ 'options' => C4::Context->preference("LinkerOptions")
+ }
+);
my $num_bibs_processed = 0;
-my $num_bibs_modified = 0;
-my $num_bad_bibs = 0;
+my $num_bibs_modified = 0;
+my $num_bad_bibs = 0;
+my %unlinked_headings;
+my %linked_headings;
+my %fuzzy_headings;
my $dbh = C4::Context->dbh;
$dbh->{AutoCommit} = 0;
-process_bibs();
+process_bibs( $linker, $bib_limit, $auth_limit, $commit );
$dbh->commit();
exit 0;
sub process_bibs {
- my $sql = "SELECT biblionumber FROM biblio ORDER BY biblionumber ASC";
+ my ( $linker, $bib_limit, $auth_limit, $commit ) = @_;
+ my $bib_where = '';
+ my $starttime = time();
+ if ($bib_limit) {
+ $bib_where = "WHERE $bib_limit";
+ }
+ my $sql =
+ "SELECT biblionumber FROM biblio $bib_where ORDER BY biblionumber ASC";
my $sth = $dbh->prepare($sql);
$sth->execute();
- while (my ($biblionumber) = $sth->fetchrow_array()) {
+ while ( my ($biblionumber) = $sth->fetchrow_array() ) {
$num_bibs_processed++;
- process_bib($biblionumber);
+ process_bib( $linker, $biblionumber );
- if (not $test_only and ($num_bibs_processed % 100) == 0) {
+ if ( not $test_only and ( $num_bibs_processed % $commit ) == 0 ) {
print_progress_and_commit($num_bibs_processed);
}
}
- if (not $test_only) {
+ if ( not $test_only ) {
$dbh->commit;
}
- print <<_SUMMARY_;
+ my $headings_linked = 0;
+ my $headings_unlinked = 0;
+ my $headings_fuzzy = 0;
+ for ( values %linked_headings ) { $headings_linked += $_; }
+ for ( values %unlinked_headings ) { $headings_unlinked += $_; }
+ for ( values %fuzzy_headings ) { $headings_fuzzy += $_; }
+
+ my $endtime = time();
+ my $totaltime = ceil (($endtime - $starttime) * 1000);
+ $starttime = strftime('%D %T', localtime($starttime));
+ $endtime = strftime('%D %T', localtime($endtime));
+
+ my $summary = <<_SUMMARY_;
Bib authority heading linking report
-------------------------------------
-Number of bibs checked: $num_bibs_processed
-Number of bibs modified: $num_bibs_modified
-Number of bibs with errors: $num_bad_bibs
+=======================================================
+Linker module: $linker_module
+Run started at: $starttime
+Run ended at: $endtime
+Total run time: $totaltime ms
+Number of bibs checked: $num_bibs_processed
+Number of bibs modified: $num_bibs_modified
+Number of bibs with errors: $num_bad_bibs
+Number of headings linked: $headings_linked
+Number of headings unlinked: $headings_unlinked
+Number of headings fuzzily linked: $headings_fuzzy
_SUMMARY_
+ $summary .= "\n**** Ran in test mode only ****\n" if $test_only;
+ print $summary;
+
+ if ($link_report) {
+ my @keys;
+ print <<_LINKED_HEADER_;
+
+Linked headings (from most frequent to least):
+-------------------------------------------------------
+
+_LINKED_HEADER_
+
+ @keys = sort {
+ $linked_headings{$b} <=> $linked_headings{$a} or "\L$a" cmp "\L$b"
+ } keys %linked_headings;
+ foreach my $key (@keys) {
+ print "$key:\t" . $linked_headings{$key} . " occurrences\n";
+ }
+
+ print <<_UNLINKED_HEADER_;
+
+Unlinked headings (from most frequent to least):
+-------------------------------------------------------
+
+_UNLINKED_HEADER_
+
+ @keys = sort {
+ $unlinked_headings{$b} <=> $unlinked_headings{$a}
+ or "\L$a" cmp "\L$b"
+ } keys %unlinked_headings;
+ foreach my $key (@keys) {
+ print "$key:\t" . $unlinked_headings{$key} . " occurrences\n";
+ }
+
+ print <<_FUZZY_HEADER_;
+
+Fuzzily-matched headings (from most frequent to least):
+-------------------------------------------------------
+
+_FUZZY_HEADER_
+
+ @keys = sort {
+ $fuzzy_headings{$b} <=> $fuzzy_headings{$a} or "\L$a" cmp "\L$b"
+ } keys %fuzzy_headings;
+ foreach my $key (@keys) {
+ print "$key:\t" . $fuzzy_headings{$key} . " occurrences\n";
+ }
+ print $summary;
+ }
}
sub process_bib {
+ my $linker = shift;
my $biblionumber = shift;
my $bib = GetMarcBiblio($biblionumber);
- unless (defined $bib) {
- print "\nCould not retrieve bib $biblionumber from the database - record is corrupt.\n";
+ unless ( defined $bib ) {
+ print
+"\nCould not retrieve bib $biblionumber from the database - record is corrupt.\n";
$num_bad_bibs++;
return;
}
- my $headings_changed = LinkBibHeadingsToAuthorities($bib);
+ my ( $headings_changed, $results ) =
+ LinkBibHeadingsToAuthorities( $linker, $bib,
+ GetFrameworkCode($biblionumber) );
+ foreach my $key ( keys %{ $results->{'unlinked'} } ) {
+ $unlinked_headings{$key} += $results->{'unlinked'}->{$key};
+ }
+ foreach my $key ( keys %{ $results->{'linked'} } ) {
+ $linked_headings{$key} += $results->{'linked'}->{$key};
+ }
+ foreach my $key ( keys %{ $results->{'fuzzy'} } ) {
+ $fuzzy_headings{$key} += $results->{'fuzzy'}->{$key};
+ }
- if ($headings_changed) {
+ if ($headings_changed) {
if ($verbose) {
- my $title = substr($bib->title, 0, 20);
- print "Bib $biblionumber ($title): $headings_changed headings changed\n";
+ my $title = substr( $bib->title, 0, 20 );
+ print
+"Bib $biblionumber ($title): $headings_changed headings changed\n";
}
- if (not $test_only) {
- # delete any item tags
- my ($itemtag, $itemsubfield) = GetMarcFromKohaField("items.itemnumber", '');
- foreach my $field ($bib->field($itemtag)) {
- $bib->delete_field($field);
- }
- ModBiblio($bib, $biblionumber, GetFrameworkCode($biblionumber));
+ if ( not $test_only ) {
+ ModBiblio( $bib, $biblionumber, GetFrameworkCode($biblionumber) );
$num_bibs_modified++;
}
}
print "... processed $recs records\n";
}
-sub print_usage {
- print <<_USAGE_;
-$0: link headings in bib records to authorities.
-
-This batch job checks each bib record in the Koha
-database and attempts to link each of its headings
-to the matching authority record.
-
-Parameters:
- --verbose print the number of headings changed
- for each bib
- --test only test the authority linking
- and report the results; do not
- change the bib records.
- --help or -h show this message.
-_USAGE_
-}
+=head1 NAME
+
+link_bibs_to_authorities.pl
+
+=head1 SYNOPSIS
+
+ link_bibs_to_authorities.pl
+ link_bibs_to_authorities.pl -v
+ link_bibs_to_authorities.pl -l
+ link_bibs_to_authorities.pl --commit=1000
+ link_bibs_to_authorities.pl --auth-limit=STRING
+ link_bibs_to_authorities.pl --bib-limit=STRING
+
+=head1 DESCRIPTION
+
+This batch job checks each bib record in the Koha database and attempts to link
+each of its headings to the matching authority record.
+
+=over 8
+
+=item B<--help>
+
+Prints this help
+
+=item B<-v|--verbose>
+
+Provide verbose log information (print the number of headings changed for each
+bib record).
+
+=item B<-l|--link-report>
+
+Provide a report of all the headings that were processed: which were matched,
+which were not, etc.
+
+=item B<--auth-limit=S>
+
+Only process those headings which match an authority record that matches the
+user-specified WHERE clause.
+
+=item B<--bib-limit=S>
+
+Only process those bib records that match the user-specified WHERE clause.
+
+=item B<--commit=N>
+
+Commit the results to the database after every N records are processed.
+
+=item B<--test>
+
+Only test the authority linking and report the results; do not change the bib
+records.
+
+=back
+
+=cut
use strict;
use warnings;
-use Test::More tests => 1;
+use Test::More tests => 3;
BEGIN {
- use_ok('C4::External::Amazon');
+ use_ok('C4::Heading');
}
+my $field = MARC::Field->new( '650', ' ', '0', a => 'Uncles', x => 'Fiction' );
+my $heading = C4::Heading->new_from_bib_field($field);
+is($heading->display_form(), 'Uncles--Fiction', 'Display form generation');
+is($heading->search_form(), 'Uncles generalsubdiv Fiction', 'Search form generation');
--- /dev/null
+#!/usr/bin/perl
+#
+# This Koha test module is a stub!
+# Add more tests here!!!
+
+use strict;
+use warnings;
+use Test::More tests => 3;
+use C4::Context;
+use C4::Heading;
+use MARC::Record;
+use MARC::Field;
+use C4::Linker::FirstMatch;
+
+
+BEGIN {
+ use_ok('C4::Linker');
+}
+my $dbh = C4::Context->dbh;
+
+my $query = "SELECT authid, marc FROM auth_header LIMIT 1;";
+my $sth = $dbh->prepare($query);
+$sth->execute();
+my ($authid, $marc) = $sth->fetchrow_array();
+SKIP: {
+ skip "No authorities", 2 unless defined $authid;
+ my $linker = C4::Linker::FirstMatch->new();
+ my $auth = MARC::Record->new_from_usmarc($marc);
+ my $fieldmatch;
+ if (C4::Context->preference('MARCFlavour') eq 'UNIMARC') {
+ $fieldmatch = '2..';
+ } else {
+ $fieldmatch = '1..';
+ }
+ my $bibfield = $auth->field($fieldmatch);
+ my $tag = $bibfield->tag();
+ $tag =~ s/^./6/;
+ $bibfield->update(tag => $tag);
+ my $heading;
+ ok(defined ($heading = C4::Heading->new_from_bib_field($bibfield, '')), "Creating heading from bib field");
+
+ my $authmatch;
+ my $fuzzy;
+ ($authmatch, $fuzzy) = $linker->get_link($heading);
+ is($authmatch, $authid, "Matched existing heading");
+}
GetAuthorityXML
GetAuthority
GetAuthType
- AUTHhtml2marc
FindDuplicateAuthority
BuildSummary
BuildUnimarcHierarchies