Bug 7417: Include see from references in bibliographic searches

This patch adds the Koha::Indexer::RecordNormalizer and
Koha::Indexer::MARC::RecordNormalizer::EmbedSeeFromHeadings packages
to enable the inclusion of alternate forms of headings in bibliographic
searches. When the new syspref IncludeSeeFromInSearches is turned on
(default is off) rebuild_zebra.pl will insert see from headings from
authority records into bibliographic records when indexing, so that a
search on an obsolete term will turn up relevant records.

To test:
1) Enable IncludeSeeFromInSearches
2) Add a heading that has an alternate form to a record (for example,
   "Cooking" has the alternate form "Cookery," if you have authority
   records from LC)
3) Index the zebraqueue (or reindex if you haven't indexed your system
   yet)
4) Confirm that if you search for "Cookery" you get the record you
   just modified

Signed-off-by: Jared Camins-Esakov <jcamins@cpbibliography.com>
Rebased on master 5 August 2012
Signed-off-by: Jared Camins-Esakov <jcamins@cpbibliography.com>
Rebased on master 11 September 2012

Signed-off-by: Katrin Fischer <Katrin.Fischer.83@web.de>

Also checked:
- Verified database update works correctly
- Checked system preference and its description
- Checked staff/opac detail pages with feature on/off
- Checked staff/opac search facets
- Downloaded and tested records in various formats
- Tried different searches for 'see from' entries of authorities
- Ran all unit tests

No problems found.
This commit is contained in:
Jared Camins-Esakov 2012-06-02 13:32:25 -04:00 committed by Paul Poulain
parent 12c48b7ff7
commit bc05b5d163
20 changed files with 836 additions and 26 deletions

View File

@ -26,6 +26,7 @@ use C4::AuthoritiesMarc::MARC21;
use C4::AuthoritiesMarc::UNIMARC;
use C4::Charset;
use C4::Log;
use Koha::Authority;
use vars qw($VERSION @ISA @EXPORT);
@ -851,19 +852,8 @@ Returns MARC::Record of the authority passed in parameter.
sub GetAuthority {
my ($authid)=@_;
my $dbh=C4::Context->dbh;
my $sth=$dbh->prepare("select authtypecode, marcxml from auth_header where authid=?");
$sth->execute($authid);
my ($authtypecode, $marcxml) = $sth->fetchrow;
my $record=eval {MARC::Record->new_from_xml(StripNonXmlChars($marcxml),'UTF-8',
(C4::Context->preference("marcflavour") eq "UNIMARC"?"UNIMARCAUTH":C4::Context->preference("marcflavour")))};
return undef if ($@);
$record->encoding('UTF-8');
if (C4::Context->preference("marcflavour") eq "MARC21") {
my ($auth_type_tag, $auth_type_subfield) = get_auth_type_location($authtypecode);
C4::AuthoritiesMarc::MARC21::fix_marc21_auth_type_location($record, $auth_type_tag, $auth_type_subfield);
}
return ($record);
my $authority = Koha::Authority->get_from_authid($authid);
return ($authority->record);
}
=head2 GetAuthType

View File

@ -477,7 +477,8 @@ sub getRecords {
# avoid first line
my $tag_num = substr($tag, 0, 3);
my $letters = substr($tag, 3);
my $field_pattern = '\n' . $tag_num . ' ([^\n]+)';
my $field_pattern = '\n' . $tag_num . ' ([^z][^\n]+)';
$field_pattern = '\n' . $tag_num . ' ([^\n]+)' if (int($tag_num) < 10);
my @field_tokens = ( $render_record =~ /$field_pattern/g ) ;
foreach my $field_token (@field_tokens) {
my @subf = ( $field_token =~ /\$([a-zA-Z0-9]) ([^\$]+)/g );

92
Koha/Authority.pm Normal file
View File

@ -0,0 +1,92 @@
package Koha::Authority;
# Copyright 2012 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
Koha::Authority - class to encapsulate authority records in Koha
=head1 SYNOPSIS
Object-oriented class that encapsulates authority records in Koha.
=head1 DESCRIPTION
Authority data.
=cut
use strict;
use warnings;
use C4::Context;
use MARC::Record;
use MARC::File::XML;
use C4::Charset;
use base qw(Class::Accessor);
__PACKAGE__->mk_accessors(qw( authid authtype record marcflavour ));
=head2 new
my $auth = Koha::Authority->new($record);
Create a new Koha::Authority object based on the provided record.
=cut
sub new {
my $class = shift;
my $record = shift;
my $self = $class->SUPER::new( { record => $record });
bless $self, $class;
return $self;
}
=head2 get_from_authid
my $auth = Koha::Authority->get_from_authid($authid);
Create the Koha::Authority object associated with the provided authid.
=cut
sub get_from_authid {
my $class = shift;
my $authid = shift;
my $marcflavour = C4::Context->preference("marcflavour");
my $dbh=C4::Context->dbh;
my $sth=$dbh->prepare("select authtypecode, marcxml from auth_header where authid=?");
$sth->execute($authid);
my ($authtypecode, $marcxml) = $sth->fetchrow;
my $record=eval {MARC::Record->new_from_xml(StripNonXmlChars($marcxml),'UTF-8',
(C4::Context->preference("marcflavour") eq "UNIMARC"?"UNIMARCAUTH":C4::Context->preference("marcflavour")))};
return undef if ($@);
$record->encoding('UTF-8');
my $self = $class->SUPER::new( { authid => $authid,
marcflavour => $marcflavour,
authtype => $authtypecode,
record => $record });
bless $self, $class;
return $self;
}
1;

View File

@ -0,0 +1,102 @@
package Koha::Filter::MARC::EmbedSeeFromHeadings;
# Copyright 2012 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
Koha::Filter::MARC::EmbedSeeFromHeadings - embeds see from headings into MARC for indexing
=head1 SYNOPSIS
=head1 DESCRIPTION
Filter to embed see from headings into MARC records.
=cut
use strict;
use warnings;
use Carp;
use Koha::Authority;
use base qw(Koha::RecordProcessor::Base);
our $NAME = 'EmbedSeeFromHeadings';
our $VERSION = '1.0';
=head2 filter
my $newrecord = $filter->filter($record);
my $newrecords = $filter->filter(\@records);
Embed see from headings into the specified record(s) and return the result.
In order to differentiate added headings from actual headings, a 'z' is
put in the first indicator.
=cut
sub filter {
my $self = shift;
my $record = shift;
my $newrecord;
return undef unless defined $record;
if (ref $record eq 'ARRAY') {
my @recarray;
foreach my $thisrec (@$record) {
push @recarray, _processrecord($thisrec);
}
$newrecord = \@recarray;
} elsif (ref $record eq 'MARC::Record') {
$newrecord = _processrecord($record);
}
return $newrecord;
}
sub _processrecord {
my $record = shift;
foreach my $field ( $record->fields() ) {
next if $field->is_control_field();
my $authid = $field->subfield('9');
next unless $authid;
my $authority = Koha::Authority->get_from_authid($authid);
next unless $authority;
my $auth_marc = $authority->record;
my @seefrom = $auth_marc->field('4..');
my @newfields;
foreach my $authfield (@seefrom) {
my $tag = substr($field->tag(), 0, 1) . substr($authfield->tag(), 1, 2);
my $newfield = MARC::Field->new($tag,
'z',
$authfield->indicator(2) || ' ',
'9' => '1');
foreach my $sub ($authfield->subfields()) {
my ($code,$val) = @$sub;
$newfield->add_subfields( $code => $val );
}
$newfield->delete_subfield( code => '9' );
push @newfields, $newfield if (scalar($newfield->subfields()) > 0);
}
$record->append_fields(@newfields);
}
return $record;
}

55
Koha/Filter/MARC/Null.pm Normal file
View File

@ -0,0 +1,55 @@
package Koha::Filter::MARC::Null;
# Copyright 2012 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
Koha::Filter::MARC::Null - an example filter that does nothing but allow us to run tests
=head1 SYNOPSIS
=head1 DESCRIPTION
Filter to allow us to run unit tests and regression tests against the
RecordProcessor.
=cut
use strict;
use warnings;
use Carp;
use base qw(Koha::RecordProcessor::Base);
our $NAME = 'Null';
our $VERSION = '1.0';
=head2 filter
my $newrecord = $filter->filter($record);
my $newrecords = $filter->filter(\@records);
Return the original record.
=cut
sub filter {
my $self = shift;
my $record = shift;
return $record;
}

183
Koha/RecordProcessor.pm Normal file
View File

@ -0,0 +1,183 @@
package Koha::RecordProcessor;
# Copyright 2012 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
Koha::RecordProcessor - Dispatcher class for record normalization
=head1 SYNOPSIS
use Koha::RecordProcessor;
my $normalizer = Koha::RecordProcessor(%params);
$normalizer->process($record)
=head1 DESCRIPTION
Dispatcher class for record normalization. RecordProcessors must
extend Koha::RecordProcessor::Base, be in the Koha::Filter namespace,
and provide the following methods:
B<filter ($record)> - apply the filter and return the result. $record
may be either a scalar or an arrayref, and the return result will be
the same type.
These methods may be overriden:
B<initialize (%params)> - initialize the filter
B<destroy ()> - destroy the filter
These methods should not be overridden unless you are very sure of what
you are doing:
B<new ()> - create a new filter object
Note that the RecordProcessor will not clone the record that is
passed in. If you do not want to change the original MARC::Record
object (or whatever type of object you are passing in), you must
clone it I<prior> to passing it off to the RecordProcessor.
=head1 FUNCTIONS
=cut
use strict;
use warnings;
use Module::Load::Conditional qw(can_load);
use Module::Pluggable::Object;
use base qw(Class::Accessor);
__PACKAGE__->mk_accessors(qw( schema filters options record ));
=head2 new
my $normalizer = Koha::RecordProcessor->new(%params);
Create a new normalizer. Available parameters are:
=over 8
=item B<schema>
Which metadata schema is in use. At the moment the only supported schema
is 'MARC'.
=item B<filters>
What filter(s) to use. This must be an arrayref to a list of filters. Filters
can be specified either with a complete class path, or, if they are in the
Koha::Filter::${schema} namespace, as only the filter name, and
"Koha::Filter::${schema}" will be prepended to it before the filter is loaded.
=back
=cut
sub new {
my $class = shift;
my $param = shift;
my $schema = $param->{schema} || 'MARC';
my $options = $param->{options} || '';
my @filters = ( );
foreach my $filter ($param->{filters}) {
next unless $filter;
my $filter_module = $filter =~ m/:/ ? $filter : "Koha::Filter::${schema}::${filter}";
if (can_load( modules => { $filter_module => undef } )) {
my $object = $filter_module->new();
$filter_module->initialize($param);
push @filters, $object;
}
}
my $self = $class->SUPER::new( { schema => $schema,
filters => \@filters,
options => $options });
bless $self, $class;
return $self;
}
=head2 bind
$normalizer->bind($record)
Bind a normalizer to a particular record.
=cut
sub bind {
my $self = shift;
my $record = shift;
$self->{record} = $record;
return;
}
=head2 process
my $newrecord = $normalizer->process([$record])
Run the record(s) through the normalization pipeline. If $record is
not specified, process the record the normalizer is bound to.
Note that $record may be either a scalar or an arrayref, and the
return value will be of the same type.
=cut
sub process {
my $self = shift;
my $record = shift || $self->record;
return unless defined $record;
my $newrecord = $record;
foreach my $filterobj (@{$self->filters}) {
next unless $filterobj;
$newrecord = $filterobj->filter($newrecord);
}
return $newrecord;
}
sub DESTROY {
my $self = shift;
foreach my $filterobj (@{$self->filters}) {
$filterobj->destroy();
}
}
=head2 AvailableFilters
my @available_filters = Koha::RecordProcessor::AvailableFilters([$schema]);
Get a list of available filters. Optionally specify the metadata schema.
At present only MARC is supported as a schema.
=cut
sub AvailableFilters {
my $schema = pop || '';
my $path = 'Koha::Filter';
$path .= "::$schema" if ($schema eq 'MARC');
my $finder = Module::Pluggable::Object->new(search_path => $path);
return $finder->plugins;
}
1;

View File

@ -0,0 +1,133 @@
package Koha::RecordProcessor::Base;
# Copyright 2012 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
Koha::RecordProcessor::Base - Base class for RecordProcessor filters
=head1 SYNOPSIS
use base qw(Koha::RecordProcessor::Base);
=head1 DESCRIPTION
Base class for record normalizer filters. RecordProcessors must
provide the following methods:
B<filter ($record)> - apply the filter and return the result. $record
may be either a scalar or an arrayref, and the return result will be
the same type.
The following variables must be defined in each filter:
our $NAME ='Filter';
our $VERSION = '1.0';
These methods may be overriden:
B<initialize (%params)> - initialize the filter
B<destroy ()> - destroy the filter
These methods should not be overridden unless you are very sure of what
you are doing:
B<new ()> - create a new filter object
Note that the RecordProcessor will not clone the record that is
passed in. If you do not want to change the original MARC::Record
object (or whatever type of object you are passing in), you must
clone it I<prior> to passing it off to the RecordProcessor.
=head1 FUNCTIONS
=cut
use strict;
use warnings;
use base qw(Class::Accessor);
__PACKAGE__->mk_ro_accessors(qw( name version ));
__PACKAGE__->mk_accessors(qw( params ));
our $NAME = 'Base';
our $VERSION = '1.0';
=head2 new
my $filter = Koha::RecordProcessor::Base->new;
Create a new filter;
=cut
sub new {
my $class = shift;
my $self = $class->SUPER::new( { });#name => $class->NAME,
#version => $class->VERSION });
bless $self, $class;
return $self;
}
=head2 initialize
$filter->initalize(%params);
Initialize a filter using the specified parameters.
=cut
sub initialize {
my $self = shift;
my $params = shift;
#$self->params = $params;
return $self;
}
=head2 destroy
$filter->destroy();
Destroy the filter.
=cut
sub destroy {
my $self = shift;
return;
}
=head2 filter
my $newrecord = $filter->filter($record);
my $newrecords = $filter->filter(\@records);
Filter the specified record(s) and return the result.
=cut
sub filter {
my $self = shift;
my $record = shift;
return $record;
}
1;

View File

@ -9,6 +9,7 @@ use List::MoreUtils qw(uniq);
use Koha::SearchEngine::Solr;
use C4::AuthoritiesMarc;
use C4::Biblio;
use Koha::RecordProcessor;
has searchengine => (
is => 'rw',
@ -39,6 +40,11 @@ sub index_record {
$record = GetAuthority( $id ) if $recordtype eq "authority";
$record = GetMarcBiblio( $id ) if $recordtype eq "biblio";
if ($record_type eq 'biblio' && C4::Context->preference('IncludeSeeFromInSearches')) {
my $normalizer = Koha::RecordProcessor->new( { filters => 'EmbedSeeFromHeadings' } );
$record = $normalizer->process($record);
}
next unless ( $record );
my $index_values = {

View File

@ -373,3 +373,4 @@ INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES (
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('AgeRestrictionMarker','','Markers for age restriction indication, e.g. FSK|PEGI|Age|',NULL,'free');
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('AgeRestrictionOverride',0,'Allow staff to check out an item with age restriction.',NULL,'YesNo');
INSERT INTO systempreferences (variable,value,explanation,type) VALUES('DidYouMeanFromAuthorities','0','Suggest searches based on authority file.','YesNo');
INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('IncludeSeeFromInSearches','0','','Include see-from references in searches.','YesNo');

View File

@ -5729,6 +5729,13 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
SetVersion($DBversion);
}
$DBversion = "3.09.00.040";
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
$dbh->do("INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('IncludeSeeFromInSearches','0','','Include see-from references in searches.','YesNo');");
print "Upgrade to $DBversion done (Add IncludeSeeFromInSearches system preference)\n";
SetVersion ($DBversion);
}
=head1 FUNCTIONS
=head2 TableExists($table)

View File

@ -83,6 +83,12 @@ Searching:
yes: Suggest
no: "Don't suggest"
- alternate searches based on data in the authority file.
- pref: IncludeSeeFromInSearches
default: 0
choices:
yes: Include
no: "Don't include"
- "<i>see from</i> (non-preferred form) headings in bibliographic searches. Please note: you will need to reindex your bibliographic database when changing this preference."
Search Form:
-
- Show tabs in OPAC and staff-side advanced search for limiting searches on the

View File

@ -336,7 +336,7 @@
<xsl:choose>
<xsl:when test="marc:datafield[@tag=100] or marc:datafield[@tag=110] or marc:datafield[@tag=111] or marc:datafield[@tag=700] or marc:datafield[@tag=710] or marc:datafield[@tag=711]">
<p class="author">by
<xsl:for-each select="marc:datafield[@tag=100 or @tag=700]">
<xsl:for-each select="marc:datafield[(@tag=100 or @tag=700) and @ind1!='z']">
<a>
<xsl:choose>
<xsl:when test="marc:subfield[@code=9] and $UseAuthoritiesForTracings='1'">
@ -351,7 +351,7 @@
<xsl:when test="position()=last()"><xsl:text>. </xsl:text></xsl:when><xsl:otherwise><xsl:text>; </xsl:text></xsl:otherwise></xsl:choose>
</xsl:for-each>
<xsl:for-each select="marc:datafield[@tag=110 or @tag=710]">
<xsl:for-each select="marc:datafield[(@tag=110 or @tag=710) and @ind1!='z']">
<a>
<xsl:choose>
<xsl:when test="marc:subfield[@code=9] and $UseAuthoritiesForTracings='1'">
@ -365,7 +365,7 @@
<xsl:choose><xsl:when test="position()=last()"><xsl:text> </xsl:text></xsl:when><xsl:otherwise><xsl:text>; </xsl:text></xsl:otherwise></xsl:choose>
</xsl:for-each>
<xsl:for-each select="marc:datafield[@tag=111 or @tag=711]">
<xsl:for-each select="marc:datafield[(@tag=111 or @tag=711) and @ind1!='z']">
<xsl:choose>
<xsl:when test="marc:subfield[@code='n']">
<xsl:text> </xsl:text>

View File

@ -283,7 +283,7 @@
<xsl:choose>
<xsl:when test="marc:datafield[@tag=100] or marc:datafield[@tag=110] or marc:datafield[@tag=111] or marc:datafield[@tag=700] or marc:datafield[@tag=710] or marc:datafield[@tag=711]">
<p class="author">av
<xsl:for-each select="marc:datafield[@tag=100 or @tag=700]">
<xsl:for-each select="marc:datafield[(@tag=100 or @tag=700) and @ind1!='z']">
<a>
<xsl:choose>
<xsl:when test="marc:subfield[@code=9] and $UseAuthoritiesForTracings='1'">
@ -298,7 +298,7 @@
<xsl:when test="position()=last()"><xsl:text>. </xsl:text></xsl:when><xsl:otherwise><xsl:text>; </xsl:text></xsl:otherwise></xsl:choose>
</xsl:for-each>
<xsl:for-each select="marc:datafield[@tag=110 or @tag=710]">
<xsl:for-each select="marc:datafield[(@tag=110 or @tag=710) and @ind1!='z']">
<a>
<xsl:choose>
<xsl:when test="marc:subfield[@code=9] and $UseAuthoritiesForTracings='1'">
@ -312,7 +312,7 @@
<xsl:choose><xsl:when test="position()=last()"><xsl:text> </xsl:text></xsl:when><xsl:otherwise><xsl:text>; </xsl:text></xsl:otherwise></xsl:choose>
</xsl:for-each>
<xsl:for-each select="marc:datafield[@tag=111 or @tag=711]">
<xsl:for-each select="marc:datafield[(@tag=111 or @tag=711) and @ind1!='z']">
<xsl:choose>
<xsl:when test="marc:subfield[@code='n']">
<xsl:text> </xsl:text>

View File

@ -450,7 +450,7 @@
<xsl:when test="marc:datafield[@tag=100] or marc:datafield[@tag=110] or marc:datafield[@tag=111] or marc:datafield[@tag=700] or marc:datafield[@tag=710] or marc:datafield[@tag=711]">
by <span class="author">
<xsl:for-each select="marc:datafield[@tag=100 or @tag=700]">
<xsl:for-each select="marc:datafield[(@tag=100 or @tag=700) and @ind1!='z']">
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:call-template name="nameABCDQ"/>.
@ -461,7 +461,7 @@
</xsl:choose>
</xsl:for-each>
<xsl:for-each select="marc:datafield[@tag=110 or @tag=710]">
<xsl:for-each select="marc:datafield[(@tag=110 or @tag=710) and @ind1!='z']">
<xsl:choose>
<xsl:when test="position()=1">
<xsl:text> -- </xsl:text>
@ -477,7 +477,7 @@
</xsl:choose>
</xsl:for-each>
<xsl:for-each select="marc:datafield[@tag=111 or @tag=711]">
<xsl:for-each select="marc:datafield[(@tag=111 or @tag=711) and @ind1!='z']">
<xsl:choose>
<xsl:when test="position()=1">
<xsl:text> -- </xsl:text>

View File

@ -325,7 +325,7 @@
<xsl:when test="marc:datafield[@tag=100] or marc:datafield[@tag=110] or marc:datafield[@tag=111] or marc:datafield[@tag=700] or marc:datafield[@tag=710] or marc:datafield[@tag=711]">
av
<xsl:for-each select="marc:datafield[@tag=100 or @tag=700]">
<xsl:for-each select="marc:datafield[(@tag=100 or @tag=700) and @ind1!='z']">
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:call-template name="nameABCDQ"/>.
@ -336,7 +336,7 @@
</xsl:choose>
</xsl:for-each>
<xsl:for-each select="marc:datafield[@tag=110 or @tag=710]">
<xsl:for-each select="marc:datafield[(@tag=110 or @tag=710) and @ind1!='z']">
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:call-template name="nameABCDN"/>.
@ -347,7 +347,7 @@
</xsl:choose>
</xsl:for-each>
<xsl:for-each select="marc:datafield[@tag=111 or @tag=711]">
<xsl:for-each select="marc:datafield[(@tag=111 or @tag=711) and @ind1!='z']">
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:call-template name="nameACDEQ"/>.

View File

@ -0,0 +1,18 @@
#!/usr/bin/perl
# This script is intended for testing RecordProcessor filters. To use it
# run the script like so:
# > perl process_record_through_filter.pl ${BIBLIONUMBER} ${FILTER}
use strict;
use warnings;
use Koha::RecordProcessor;
use Data::Dumper;
use C4::Biblio;
my $record = GetMarcBiblio($ARGV[0]);
print "Before: " . $record->as_formatted() . "\n";
my $processor = Koha::RecordProcessor->new( { filters => ( $ARGV[1] ) });
$record = $processor->process($record);
print "After : " . $record->as_formatted() . "\n";

View File

@ -10,6 +10,7 @@ use File::Path;
use C4::Biblio;
use C4::AuthoritiesMarc;
use C4::Items;
use Koha::RecordProcessor;
#
# script that checks zebradir structure & create directories & mandatory files if needed
@ -497,6 +498,9 @@ sub get_corrected_marc_record {
fix_leader($marc);
if ($record_type eq 'authority') {
fix_authority_id($marc, $record_number);
} elsif ($record_type eq 'biblio' && C4::Context->preference('IncludeSeeFromInSearches')) {
my $normalizer = Koha::RecordProcessor->new( { filters => 'EmbedSeeFromHeadings' } );
$marc = $normalizer->process($marc);
}
if (C4::Context->preference("marcflavour") eq "UNIMARC") {
fix_unimarc_100($marc);

80
t/RecordProcessor.t Executable file
View File

@ -0,0 +1,80 @@
#!/usr/bin/perl
# Copyright 2012 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 File::Spec;
use MARC::Record;
use Test::More;
BEGIN {
use_ok('Koha::RecordProcessor');
}
my $isbn = '0590353403';
my $title = 'Foundation';
my $marc_record=MARC::Record->new;
my $field = MARC::Field->new('020','','','a' => $isbn);
$marc_record->append_fields($field);
$field = MARC::Field->new('245','','','a' => $title);
$marc_record->append_fields($field);
my $filterdir = File::Spec->rel2abs('Koha/Filter') . '/MARC';
opendir(my $dh, $filterdir);
my @installed_filters = map { ( /\.pm$/ && -f "$filterdir/$_" && s/\.pm$// ) ? "Koha::Filters::MARC::$_" : () } readdir($dh);
my @available_filters = Koha::RecordProcessor::AvailableFilters();
foreach my $filter (@installed_filters) {
ok(grep($filter, @available_filters), "Found filter $filter");
}
my $marc_filters = grep (/MARC/, @available_filters);
is(scalar Koha::RecordProcessor::AvailableFilters('MARC'), $marc_filters, 'Retrieved list of MARC filters');
my $processor = Koha::RecordProcessor->new( { filters => ( 'ABCD::EFGH::IJKL' ) } );
is(ref($processor), 'Koha::RecordProcessor', 'Created record processor with invalid filter');
is($processor->process($marc_record), $marc_record, 'Process record with empty processor');
$processor = Koha::RecordProcessor->new( { filters => ( 'Null' ) } );
is(ref($processor->filters->[0]), 'Koha::Filter::MARC::Null', 'Created record processor with implicitly scoped Null filter');
$processor = Koha::RecordProcessor->new( { filters => ( 'Koha::Filter::MARC::Null' ) } );
is(ref($processor->filters->[0]), 'Koha::Filter::MARC::Null', 'Created record processor with explicitly scoped Null filter');
is($processor->process($marc_record), $marc_record, 'Process record');
$processor->bind($marc_record);
is($processor->record, $marc_record, 'Bound record to processor');
is($processor->process(), $marc_record, 'Filter bound record');
eval {
$processor = Koha::RecordProcessor->new( { filters => ( 'Koha::Filter::MARC::Null' ) } );
undef $processor;
};
ok(!$@, 'Destroyed processor successfully');
done_testing();

66
t/db_dependent/Koha_Authority.t Executable file
View File

@ -0,0 +1,66 @@
#!/usr/bin/perl
# Copyright 2012 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 C4::Context;
use Test::More;
BEGIN {
use_ok('Koha::Authority');
}
my $record = MARC::Record->new;
$record->add_fields(
[ '001', '1234' ],
[ '150', ' ', ' ', a => 'Cooking' ],
[ '450', ' ', ' ', a => 'Cookery' ],
);
my $authority = Koha::Authority->new($record);
is(ref($authority), 'Koha::Authority', 'Created valid Koha::Authority object');
is_deeply($authority->record, $record, 'Saved record');
SKIP:
{
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare("SELECT authid FROM auth_header LIMIT 1;");
$sth->execute();
my $authid;
for my $row ($sth->fetchrow_hashref) {
$authid = $row->{'authid'};
}
skip 'No authorities', 3 unless $authid;
$authority = Koha::Authority->get_from_authid($authid);
is(ref($authority), 'Koha::Authority', 'Retrieved valid Koha::Authority object');
is($authority->authid, $authid, 'Object authid is correct');
is($authority->record->field('001')->data(), $authid, 'Retrieved correct record');
$authority = Koha::Authority->get_from_authid('alphabetsoup');
is($authority, undef, 'No invalid record is retrieved');
}
done_testing();

View File

@ -0,0 +1,66 @@
#!/usr/bin/perl
# Copyright 2012 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 File::Spec;
use MARC::Record;
use Koha::Authority;
use Test::More;
use Test::MockModule;
BEGIN {
use_ok('Koha::RecordProcessor');
}
my $module = new Test::MockModule('MARC::Record');
$module->mock('new_from_xml', sub {
my $record = MARC::Record->new;
$record->add_fields(
[ '001', '1234' ],
[ '150', ' ', ' ', a => 'Cooking' ],
[ '450', ' ', ' ', a => 'Cookery' ],
);
return $record;
});
my $bib = MARC::Record->new;
$bib->add_fields(
[ '245', '0', '4', a => 'The Ifrane cookbook' ],
[ '650', ' ', ' ', a => 'Cooking', 9 => '1234' ]
);
my $resultbib = MARC::Record->new;
$resultbib->add_fields(
[ '245', '0', '4', a => 'The Ifrane cookbook' ],
[ '650', ' ', ' ', a => 'Cooking', 9 => '1234' ],
[ '650', 'z', ' ', a => 'Cookery' ]
);
my $processor = Koha::RecordProcessor->new( { filters => ( 'EmbedSeeFromHeadings' ) } );
is(ref($processor), 'Koha::RecordProcessor', 'Created record processor');
my $result = $processor->process($bib);
is_deeply($result, $resultbib, 'Inserted see-from heading to record');
done_testing();