Bug 35659: OAI Harvester
Test plan: - Run updatedatabase.pl - Apply the DBIC update patch - Setup an OAI repository in Administration -> OAI repositories (admin/oaiservers.pl) If the repository dataformat is in oai_dc, you can use the sample XSLT files: For Unimarc: OAIDCtoUNIMARCXML.xsl for bibliographic records AuthOAIDCtoUNIMARCXML.xsl for authorities For Marc21: OAIDCtoMARC21XML.xsl for bibliographic records AuthOAIDCtoMARC21XML.xsl for authorities If the repository dataformat is in marc-xml, you can use OAIMarcxml2KohaMarcxml.xsl for both Unimarc and Marc21. - Some repositories to test with: Bibliographic records, oai_dc: Endpoint: http://staroai.theses.fr/OAIHandler Set: ddc:260 XSLT: <path_to_src>/koha-tmpl/intranet-tmpl/prog/en/xslt/OAIDCtoUNIMARCXML.xsl or XSLT: <path_to_src>/koha-tmpl/intranet-tmpl/prog/en/xslt/OAIDCtoMARC21XML.xsl Authorities, oai_dc: Endpoint: https://www.idref.fr/OAI/oai.jsp Set: a XSLT: <path_to_src>/koha-tmpl/intranet-tmpl/prog/en/xslt/AuthOAIDCtoUNIMARCXML.xsl or XSLT: <path_to_src>/koha-tmpl/intranet-tmpl/prog/en/xslt/AuthOAIDCtoMARC21XML.xsl Authorities, marc-xml, Unimarc: Endpoint: https://www.idref.fr/OAI/oai.jsp Set: a XSLT: <path_to_src>/koha-tmpl/intranet-tmpl/prog/en/xslt/OAIMarcxml2KohaMarcxml.xsl - Note: marc-xml harvesting will not work with HTTP::OAI::Harvester version 3.xx Version 4.xx is needed. See Bug 17704 for updating Koha default version to 4.xx - If you want to receive a report email, fill the OAI-PMH:HarvestEmailReport syspref. The model used (OAI_HARVEST_REPORT) can be edited in tools -> Notices and slips. - start a harvest with the following command: misc/cronjobs/harvest_oai.pl This script starts an OAI Harvest This script has the following parameters : -h --help: this message -v --verbose (enable output to stdout) -r --repository: id of the OAI repository -d --days: number of days to harvest from (optional) -l --list: list the OAI repositories -f --force: force harvesting (ignore records datestamps) (optional) Example: misc/cronjobs/harvest_oai.pl -r 1 -d 10 -v -f - Check the logs in the Log Viewer (tools/viewlog.pl) (CronjobLog syspref must be activated) Sponsored-by: KohaLa Signed-off-by: Michal Denar <black23@gmail.com> Signed-off-by: Julian Maurice <julian.maurice@biblibre.com> Signed-off-by: Pedro Amorim <pedro.amorim@ptfs-europe.com> Signed-off-by: Victor Grousset/tuxayo <victor@tuxayo.net> Signed-off-by: David Cook <dcook@prosentient.com.au> Sponsored-by: Association KohaLa - https://koha-fr.org/ Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
This commit is contained in:
parent
474148538f
commit
d2367657b2
|
|
@ -0,0 +1,51 @@
|
|||
package Koha::Import::Oaipmh::Authorities;
|
||||
|
||||
# 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 3 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
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use Koha::Import::Oaipmh::Authority;
|
||||
|
||||
use base qw(Koha::Objects);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::Import::Oaipmh::Authorities
|
||||
|
||||
This object represents a collection of OAI-PMH records being imported as authorities
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Methods
|
||||
|
||||
|
||||
=head3 type
|
||||
|
||||
=cut
|
||||
|
||||
sub _type {
|
||||
return 'ImportOaipmhAuthority';
|
||||
}
|
||||
|
||||
=head3 object_class
|
||||
|
||||
Koha::Object class
|
||||
|
||||
=cut
|
||||
|
||||
sub object_class {
|
||||
return 'Koha::Import::Oaipmh::Authority';
|
||||
}
|
||||
1;
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package Koha::Import::Oaipmh::Authority;
|
||||
|
||||
# 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 3 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
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use base qw(Koha::Object);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::Import::Oaipmh::Authority
|
||||
|
||||
This object represents an OAI-PMH record being imported as an authority
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Class Methods
|
||||
|
||||
=cut
|
||||
|
||||
=head3 _type
|
||||
|
||||
=cut
|
||||
|
||||
sub _type {
|
||||
return 'ImportOaipmhAuthority';
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package Koha::Import::Oaipmh::Biblio;
|
||||
|
||||
# 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 3 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
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use base qw(Koha::Object);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::Import::Oaipmh::Biblio
|
||||
|
||||
This object represents an OAI-PMH record being imported as a bibliographic record
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Methods
|
||||
|
||||
|
||||
=head3 _type
|
||||
|
||||
=cut
|
||||
|
||||
sub _type {
|
||||
return 'ImportOaipmhBiblio';
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package Koha::Import::Oaipmh::Biblios;
|
||||
|
||||
# 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 3 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
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use Koha::Import::Oaipmh::Biblio;
|
||||
|
||||
use base qw(Koha::Objects);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::Import::Oaipmh::Biblios
|
||||
|
||||
This object represents a collection of OAI-PMH records being imported as bibliographic records
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Methods
|
||||
|
||||
|
||||
=head3 type
|
||||
|
||||
=cut
|
||||
|
||||
sub _type {
|
||||
return 'ImportOaipmhBiblio';
|
||||
}
|
||||
|
||||
=head3 object_class
|
||||
|
||||
Koha::Object class
|
||||
|
||||
=cut
|
||||
|
||||
sub object_class {
|
||||
return 'Koha::Import::Oaipmh::Biblio';
|
||||
}
|
||||
1;
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
# Copyright BibLibre 2023
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses>.
|
||||
|
||||
package Koha::OAI::Client::Harvester;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::OAI::Client::Harvester - OAI Harvester
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Koha::OAI::Client::Harvester contains OAI-PMH harvester main functions
|
||||
|
||||
=cut
|
||||
|
||||
use utf8;
|
||||
use open qw( :std :utf8 );
|
||||
|
||||
use C4::Biblio qw( AddBiblio GetFrameworkCode ModBiblio DelBiblio );
|
||||
use C4::AuthoritiesMarc qw (AddAuthority GuessAuthTypeCode ModAuthority DelAuthority );
|
||||
use C4::Log qw( cronlogaction );
|
||||
use HTTP::OAI;
|
||||
use HTTP::OAI::Metadata::OAI_DC;
|
||||
use Koha::DateUtils qw( dt_from_string );
|
||||
use Koha::OaiServers;
|
||||
use Koha::Import::Oaipmh::Biblio;
|
||||
use Koha::Import::Oaipmh::Biblios;
|
||||
use Koha::Import::Oaipmh::Authority;
|
||||
use Koha::Import::Oaipmh::Authorities;
|
||||
use Koha::XSLT::Base;
|
||||
use MARC::File::XML;
|
||||
use MARC::Record;
|
||||
use Modern::Perl;
|
||||
use DateTime;
|
||||
use DateTime::Format::Strptime;
|
||||
use Try::Tiny qw( catch try );
|
||||
use Date::Calc qw(
|
||||
Add_Delta_Days
|
||||
Today
|
||||
);
|
||||
|
||||
my $strp = DateTime::Format::Strptime->new(
|
||||
pattern => '%FT%TZ',
|
||||
time_zone => 'floating',
|
||||
);
|
||||
|
||||
our $verbose = 0;
|
||||
our $server;
|
||||
our $force = 0;
|
||||
our $days = 0;
|
||||
our $xslt_engine = Koha::XSLT::Base->new;
|
||||
|
||||
=head2 new
|
||||
|
||||
$harvester = Koha::OAI::Client::Harvester->new( { server => $server, verbose => $verbose, days => $days, force => $force } );
|
||||
|
||||
New instance of Koha::OAI::Client::Harvester
|
||||
|
||||
C<$server> An OAI repository (Koha::OaiServer)
|
||||
|
||||
C<$verbose> print log messages to stdout when enabled
|
||||
|
||||
C<$days> number of days to harvest from (optional)
|
||||
|
||||
C<$force> force harvesting (ignore records datestamps)
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
|
||||
my ( $self, $args ) = @_;
|
||||
|
||||
$server = $args->{'server'};
|
||||
$verbose = $args->{'verbose'};
|
||||
$days = $args->{'days'};
|
||||
$force = $args->{'force'};
|
||||
return $self;
|
||||
}
|
||||
|
||||
=head2 init
|
||||
|
||||
Starts harvesting
|
||||
|
||||
=cut
|
||||
|
||||
sub init {
|
||||
my ( $self, $args ) = @_;
|
||||
|
||||
printlog("Starting OAI Harvest from repository");
|
||||
|
||||
my $h = HTTP::OAI::Harvester->new(
|
||||
repository => HTTP::OAI::Identify->new(
|
||||
baseURL => $server->endpoint,
|
||||
version => '2.0',
|
||||
)
|
||||
);
|
||||
|
||||
printlog( "Using HTTP::OAI::Harvester version " . $HTTP::OAI::Harvester::VERSION );
|
||||
|
||||
printlog( "Using endpoint "
|
||||
. $server->endpoint
|
||||
. ", set "
|
||||
. $server->oai_set
|
||||
. ", dataformat "
|
||||
. $server->dataformat
|
||||
. ", recordtype "
|
||||
. $server->recordtype );
|
||||
|
||||
try {
|
||||
my $lmdf = $h->ListMetadataFormats();
|
||||
my $lmdflog = "";
|
||||
for ( $lmdf->metadataFormat ) {
|
||||
$lmdflog .= $_->metadataPrefix . " ";
|
||||
}
|
||||
printlog("Available metadata formats for this repository: $lmdflog");
|
||||
} catch {
|
||||
printlog("ListMetadataFormats failed");
|
||||
};
|
||||
|
||||
if ( $server->add_xslt ) {
|
||||
printlog( "Using XSLT file " . $server->add_xslt );
|
||||
} else {
|
||||
printlog("Not using an XSLT file");
|
||||
}
|
||||
|
||||
my $start_date = '';
|
||||
my $today_date = '';
|
||||
|
||||
if ($days) {
|
||||
|
||||
# Change this to yyyy-mm-dd
|
||||
my $dt_today = dt_from_string();
|
||||
my ( $nowyear, $nowmonth, $nowday ) = Today();
|
||||
my @date = Add_Delta_Days( $nowyear, $nowmonth, $nowday, -$days );
|
||||
my $dt_start = DateTime->new( year => $date[0], month => $date[1], day => $date[2] );
|
||||
$start_date = $dt_start->ymd();
|
||||
printlog("Harvesting from $start_date");
|
||||
}
|
||||
|
||||
printlog("Asking for records");
|
||||
my $response = $h->ListRecords(
|
||||
metadataPrefix => $server->dataformat,
|
||||
set => $server->oai_set,
|
||||
from => $start_date,
|
||||
);
|
||||
if ( $response->is_error ) {
|
||||
printlog( "Error requesting ListRecords: " . $response->code . " " . $response->message );
|
||||
exit;
|
||||
}
|
||||
printlog( "Request URL: " . $response->requestURL );
|
||||
|
||||
my %stats;
|
||||
my @statuses = qw(added updated deleted in_error skipped total);
|
||||
foreach my $status (@statuses) {
|
||||
$stats{$status} = 0;
|
||||
}
|
||||
|
||||
printlog("Starting processing results");
|
||||
while ( my $oai_record = $response->next ) {
|
||||
$stats{'total'}++;
|
||||
my $status = $self->processRecord($oai_record);
|
||||
$stats{$status}++;
|
||||
}
|
||||
|
||||
my $results = '';
|
||||
foreach my $status (@statuses) {
|
||||
$results .= $stats{$status} . " $status\n";
|
||||
}
|
||||
printlog( "Harvest results:\n" . $results );
|
||||
|
||||
if ( C4::Context->preference("OAI-PMH:HarvestEmailReport") ) {
|
||||
|
||||
my $letter = C4::Letters::GetPreparedLetter(
|
||||
(
|
||||
module => 'catalogue',
|
||||
letter_code => 'OAI_HARVEST_REPORT',
|
||||
substitute => {
|
||||
servername => $server->servername,
|
||||
endpoint => $server->endpoint,
|
||||
set => $server->oai_set,
|
||||
dataformat => $server->dataformat,
|
||||
recordtype => $server->recordtype,
|
||||
added => $stats{'added'},
|
||||
updated => $stats{'updated'},
|
||||
deleted => $stats{'deleted'},
|
||||
skipped => $stats{'skipped'},
|
||||
in_error => $stats{'in_error'},
|
||||
total => $stats{'total'}
|
||||
},
|
||||
)
|
||||
) or printlog("OAI_HARVEST_REPORT letter not found");
|
||||
|
||||
my $success = C4::Letters::EnqueueLetter(
|
||||
{
|
||||
letter => $letter,
|
||||
to_address => C4::Context->preference("OAI-PMH:HarvestEmailReport"), message_transport_type => 'email'
|
||||
}
|
||||
);
|
||||
if ($success) {
|
||||
printlog("Email report enqueued");
|
||||
} else {
|
||||
printlog("Unable to enqueue report email");
|
||||
}
|
||||
}
|
||||
|
||||
printlog("Ending OAI Harvest from repository");
|
||||
}
|
||||
|
||||
=head2 processRecord
|
||||
|
||||
This method processes an incoming OAI record
|
||||
|
||||
=cut
|
||||
|
||||
sub processRecord {
|
||||
my $self = shift;
|
||||
my $oai_record = shift;
|
||||
my $status = '';
|
||||
unless ( $oai_record->identifier ) {
|
||||
printlog("No identifier found");
|
||||
$status = 'skipped';
|
||||
return $status;
|
||||
}
|
||||
|
||||
my $to_delete;
|
||||
my $outputUnimarc;
|
||||
my $marcrecord;
|
||||
if ( $oai_record->status && $oai_record->status eq "deleted" ) {
|
||||
$to_delete = 1;
|
||||
} else {
|
||||
if ( $server->add_xslt ) {
|
||||
$outputUnimarc = $xslt_engine->transform( $oai_record->metadata->dom, $server->add_xslt );
|
||||
my $err = $xslt_engine->err;
|
||||
if ($err) {
|
||||
printlog("XSLT::Base error: $err");
|
||||
$status = 'in_error';
|
||||
return $status;
|
||||
}
|
||||
} else {
|
||||
$outputUnimarc = $oai_record->metadata->dom;
|
||||
}
|
||||
$marcrecord = MARC::Record->new_from_xml( $outputUnimarc, 'UTF-8' );
|
||||
}
|
||||
my $imported_record;
|
||||
if ( $server->recordtype eq "biblio" ) {
|
||||
$imported_record = Koha::Import::Oaipmh::Biblios->find(
|
||||
{
|
||||
repository => $server->endpoint,
|
||||
identifier => $oai_record->identifier,
|
||||
recordtype => $server->recordtype,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$imported_record = Koha::Import::Oaipmh::Authorities->find(
|
||||
{
|
||||
repository => $server->endpoint,
|
||||
identifier => $oai_record->identifier,
|
||||
recordtype => $server->recordtype,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ($imported_record) {
|
||||
if ($to_delete) {
|
||||
if ( $server->recordtype eq "biblio" ) {
|
||||
my $biblionumber = $imported_record->biblionumber;
|
||||
my $error = DelBiblio($biblionumber);
|
||||
if ($error) {
|
||||
printlog(
|
||||
"Record " . $oai_record->identifier . " not deleted, biblionumber: $biblionumber ($error)" );
|
||||
$status = 'in_error';
|
||||
} else {
|
||||
$imported_record->delete;
|
||||
printlog( "Record " . $oai_record->identifier . " deleted, biblionumber: $biblionumber" );
|
||||
$status = 'deleted';
|
||||
}
|
||||
} else {
|
||||
my $authid = $imported_record->authid;
|
||||
DelAuthority( { authid => $authid } );
|
||||
$imported_record->delete;
|
||||
printlog( "Record " . $oai_record->identifier . " deleted, authid: $authid" );
|
||||
$status = 'deleted';
|
||||
}
|
||||
} else {
|
||||
my $existing_dt = $strp->parse_datetime( $imported_record->datestamp );
|
||||
my $incoming_dt = $strp->parse_datetime( $oai_record->datestamp );
|
||||
|
||||
if ( $force || !$incoming_dt || !$existing_dt || $incoming_dt > $existing_dt ) {
|
||||
if ( $server->recordtype eq "biblio" ) {
|
||||
my $biblionumber = $imported_record->biblionumber;
|
||||
my $result = ModBiblio( $marcrecord, $biblionumber, GetFrameworkCode($biblionumber) );
|
||||
printlog( "Record " . $oai_record->identifier . " updated, biblionumber: $biblionumber" );
|
||||
} else {
|
||||
my $authid = $imported_record->authid;
|
||||
my $result = ModAuthority( $authid, $marcrecord, GuessAuthTypeCode($marcrecord) );
|
||||
printlog( "Record " . $oai_record->identifier . " updated, authid: $authid" );
|
||||
}
|
||||
$imported_record->update(
|
||||
{
|
||||
datestamp => $imported_record->datestamp,
|
||||
}
|
||||
);
|
||||
$status = 'updated';
|
||||
} else {
|
||||
printlog( "Record "
|
||||
. $oai_record->identifier
|
||||
. " skipped (incoming record was not newer than existing record)" );
|
||||
$status = 'skipped';
|
||||
}
|
||||
}
|
||||
} elsif ( !$to_delete ) {
|
||||
if ( $server->recordtype eq "biblio" ) {
|
||||
my ( $biblionumber, $biblioitemnumber ) = AddBiblio($marcrecord);
|
||||
printlog( $oai_record->identifier . " added, biblionumber: $biblionumber" );
|
||||
Koha::Import::Oaipmh::Biblio->new(
|
||||
{
|
||||
repository => $server->endpoint,
|
||||
identifier => $oai_record->identifier,
|
||||
biblionumber => $biblionumber,
|
||||
recordtype => $server->recordtype,
|
||||
datestamp => $oai_record->datestamp,
|
||||
}
|
||||
)->store;
|
||||
} else {
|
||||
my $authid = AddAuthority( $marcrecord, "", GuessAuthTypeCode($marcrecord) );
|
||||
printlog( $oai_record->identifier . " added, authid: $authid" );
|
||||
Koha::Import::Oaipmh::Authority->new(
|
||||
{
|
||||
repository => $server->endpoint,
|
||||
identifier => $oai_record->identifier,
|
||||
authid => $authid,
|
||||
recordtype => $server->recordtype,
|
||||
datestamp => $oai_record->datestamp,
|
||||
}
|
||||
)->store;
|
||||
}
|
||||
$status = 'added';
|
||||
} else {
|
||||
printlog( "Record " . $oai_record->identifier . " skipped (record not present or already deleted)" );
|
||||
$status = 'skipped';
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
=head2 printlog
|
||||
|
||||
This method adds a cronlog and prints to stdout if verbose is enabled
|
||||
|
||||
=cut
|
||||
|
||||
sub printlog {
|
||||
my $message = shift;
|
||||
$message = $server->servername . ": " . $message;
|
||||
print $message . "\n" if ($verbose);
|
||||
cronlogaction( { info => $message } );
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package Koha::OaiServer;
|
||||
|
||||
# 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 3 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, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
|
||||
use Koha::Database;
|
||||
|
||||
use base qw(Koha::Object);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::OaiServer - Koha OaiServer Object class
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Class Methods
|
||||
|
||||
=cut
|
||||
|
||||
=head3 _type
|
||||
|
||||
Return type of Object relating to Schema ResultSet
|
||||
|
||||
=cut
|
||||
|
||||
sub _type {
|
||||
return 'Oaiserver';
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package Koha::OaiServers;
|
||||
|
||||
# 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 3 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, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
|
||||
use Koha::Database;
|
||||
|
||||
use Koha::OaiServer;
|
||||
|
||||
use base qw(Koha::Objects);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::OaiServers - Koha OaiServer Object set class
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Class Methods
|
||||
|
||||
=cut
|
||||
|
||||
=head3 _type
|
||||
|
||||
Return type of object, relating to Schema ResultSet
|
||||
|
||||
=cut
|
||||
|
||||
sub _type {
|
||||
return 'Oaiserver';
|
||||
}
|
||||
|
||||
=head3 object_class
|
||||
|
||||
Return object class
|
||||
|
||||
=cut
|
||||
|
||||
sub object_class {
|
||||
return 'Koha::OaiServer';
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# 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 3 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, see <http://www.gnu.org/licenses>.
|
||||
|
||||
# This script is used to maintain the OAI servers table.
|
||||
# Parameter $op is operation: list, new, edit, add_validated, delete_confirmed.
|
||||
# add_validated saves a validated record and goes to list view.
|
||||
# delete_confirmed deletes a record and goes to list view.
|
||||
|
||||
use Modern::Perl;
|
||||
use CGI qw ( -utf8 );
|
||||
use C4::Context;
|
||||
use C4::Auth qw( get_template_and_user );
|
||||
use C4::Output qw( output_html_with_http_headers );
|
||||
use Koha::Database;
|
||||
use Koha::OaiServers;
|
||||
|
||||
# Initialize CGI, template, database
|
||||
|
||||
my $input = CGI->new;
|
||||
my $op = $input->param('op') || 'list';
|
||||
my $id = $input->param('id') || 0;
|
||||
my $type = $input->param('type') || '';
|
||||
my $searchfield = '';
|
||||
|
||||
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
|
||||
{
|
||||
template_name => "admin/oaiservers.tt",
|
||||
query => $input,
|
||||
type => "intranet",
|
||||
flagsrequired => { parameters => 'manage_search_targets' },
|
||||
}
|
||||
);
|
||||
my $script_name = "/cgi-bin/koha/admin/oaiservers.pl";
|
||||
my $path = C4::Context->config('intrahtdocs') . "/prog/";
|
||||
|
||||
$template->param( script_name => $script_name, xslt_path => $path );
|
||||
|
||||
my $schema = Koha::Database->new()->schema();
|
||||
|
||||
# Main code
|
||||
# First process a confirmed delete, or save a validated record
|
||||
|
||||
if ( $op eq 'delete_confirmed' && $id ) {
|
||||
my $server = Koha::OaiServers->find($id);
|
||||
if ($server) {
|
||||
$server->delete;
|
||||
$template->param( msg_deleted => 1, msg_add => $server->servername );
|
||||
} else {
|
||||
$template->param( msg_notfound => 1, msg_add => $id );
|
||||
}
|
||||
$id = 0;
|
||||
} elsif ( $op eq 'add_validated' ) {
|
||||
my @fields = qw/endpoint oai_set dataformat
|
||||
recordtype servername
|
||||
add_xslt/;
|
||||
my $formdata = _form_data_hashref( $input, \@fields );
|
||||
if ($id) {
|
||||
my $server = Koha::OaiServers->find($id);
|
||||
if ($server) {
|
||||
$server->set($formdata)->store;
|
||||
$template->param( msg_updated => 1, msg_add => $formdata->{servername} );
|
||||
} else {
|
||||
$template->param( msg_notfound => 1, msg_add => $id );
|
||||
}
|
||||
$id = 0;
|
||||
} else {
|
||||
Koha::OaiServer->new($formdata)->store;
|
||||
$template->param( msg_added => 1, msg_add => $formdata->{servername} );
|
||||
}
|
||||
} else {
|
||||
|
||||
#use searchfield only in remaining operations
|
||||
$searchfield = $input->param('searchfield') || '';
|
||||
}
|
||||
|
||||
# Now list multiple records, or edit one record
|
||||
|
||||
my $data = [];
|
||||
if ( $op eq 'add' || $op eq 'edit' ) {
|
||||
$data = ServerSearch( $schema, $id, $searchfield ) if $searchfield || $id;
|
||||
delete $data->[0]->{id} if @$data && $op eq 'add'; #cloning record
|
||||
$template->param(
|
||||
add_form => 1, server => @$data ? $data->[0] : undef,
|
||||
op => $op, type => $op eq 'add' ? lc $type : ''
|
||||
);
|
||||
} else {
|
||||
$data = ServerSearch( $schema, $id, $searchfield );
|
||||
$template->param(
|
||||
loop => \@$data, searchfield => $searchfield, id => $id,
|
||||
op => 'list'
|
||||
);
|
||||
}
|
||||
output_html_with_http_headers $input, $cookie, $template->output;
|
||||
|
||||
# End of main code
|
||||
|
||||
sub ServerSearch { #find server(s) by id or name
|
||||
my ( $schema, $id, $searchstring ) = @_;
|
||||
|
||||
return Koha::OaiServers->search(
|
||||
$id ? { id => $id } : { servername => { like => $searchstring . '%' } },
|
||||
)->unblessed;
|
||||
}
|
||||
|
||||
sub _form_data_hashref {
|
||||
my ( $input, $fieldref ) = @_;
|
||||
return { map { ( $_ => scalar $input->param($_) // '' ) } @$fieldref };
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
use Modern::Perl;
|
||||
|
||||
return {
|
||||
bug_number => "35659",
|
||||
description => "OAI-PMH Harvester",
|
||||
up => sub {
|
||||
my ($args) = @_;
|
||||
my ( $dbh, $out ) = @$args{qw(dbh out)};
|
||||
$dbh->do(
|
||||
q{
|
||||
CREATE TABLE IF NOT EXISTS `oaiservers` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique identifier assigned by Koha',
|
||||
`endpoint` varchar(255) NOT NULL COMMENT 'OAI endpoint (host + port + path)',
|
||||
`oai_set` varchar(255) DEFAULT NULL COMMENT 'OAI set to harvest',
|
||||
`servername` longtext NOT NULL COMMENT 'name given to the target by the library',
|
||||
`dataformat` enum('oai_dc','marc-xml', 'marcxml') NOT NULL DEFAULT 'oai_dc' COMMENT 'data format',
|
||||
`recordtype` enum('authority','biblio') NOT NULL DEFAULT 'biblio' COMMENT 'server contains bibliographic or authority records',
|
||||
`add_xslt` longtext DEFAULT NULL COMMENT 'zero or more paths to XSLT files to be processed on the search results',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
}
|
||||
);
|
||||
say $out "Added new table 'oaiservers'";
|
||||
|
||||
$dbh->do(
|
||||
q{
|
||||
CREATE TABLE IF NOT EXISTS `import_oaipmh_biblios` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique identifier assigned by Koha',
|
||||
`biblionumber` int(11) NOT NULL COMMENT 'unique identifier assigned to each koha record',
|
||||
`identifier` varchar(255) NOT NULL COMMENT 'OAI record identifier',
|
||||
`repository` varchar(255) NOT NULL COMMENT 'OAI repository',
|
||||
`recordtype` enum('authority','biblio') NOT NULL DEFAULT 'biblio' COMMENT 'is the record bibliographic or authority',
|
||||
`datestamp` varchar(255) DEFAULT NULL COMMENT 'OAI set to harvest',
|
||||
`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
KEY biblionumber (biblionumber),
|
||||
CONSTRAINT FK_import_oaipmh_biblios_1 FOREIGN KEY (biblionumber) REFERENCES biblio (biblionumber) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
}
|
||||
);
|
||||
|
||||
$dbh->do(
|
||||
q{
|
||||
CREATE TABLE IF NOT EXISTS `import_oaipmh_authorities` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique identifier assigned by Koha',
|
||||
`authid` bigint(20) unsigned NOT NULL COMMENT 'unique identifier assigned to each koha record',
|
||||
`identifier` varchar(255) NOT NULL COMMENT 'OAI record identifier',
|
||||
`repository` varchar(255) NOT NULL COMMENT 'OAI repository',
|
||||
`recordtype` enum('authority','biblio') NOT NULL DEFAULT 'biblio' COMMENT 'is the record bibliographic or authority',
|
||||
`datestamp` varchar(255) DEFAULT NULL COMMENT 'OAI set to harvest',
|
||||
`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
KEY authid (authid),
|
||||
CONSTRAINT FK_import_oaipmh_authorities_1 FOREIGN KEY (authid) REFERENCES auth_header (authid) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
}
|
||||
);
|
||||
say $out "Added new tables 'import_oaipmh_biblios' and import_oaipmh_authorities";
|
||||
|
||||
$dbh->do(
|
||||
q{
|
||||
UPDATE `permissions` SET description='Manage Z39.50 and SRU servers, OAI repositories configuration' WHERE code='manage_search_targets';
|
||||
}
|
||||
);
|
||||
say $out "Updated manage_search_targets permission description";
|
||||
|
||||
$dbh->do(
|
||||
q{
|
||||
INSERT IGNORE INTO systempreferences (variable, value, options, explanation, type) VALUES
|
||||
('OAI-PMH:HarvestEmailReport','','','If set, a report email will be sent to this address after an OAI harvest','Free');
|
||||
}
|
||||
);
|
||||
say $out "Added OAI-PMH:HarvestEmailReport system preference";
|
||||
|
||||
$dbh->do(
|
||||
q{
|
||||
INSERT IGNORE INTO letter
|
||||
(module, code, branchcode, name, is_html, title, content, message_transport_type, lang)
|
||||
VALUES ('catalogue','OAI_HARVEST_REPORT','','OAI Harvest Report',0,'OAI Harvest report for [% servername %]','OAI Harvest report for [% servername %]:\n\nEndpoint: [% endpoint %]\nSet: [% set %]\nData format: [% dataformat %]\nRecord type: [% recordtype %]\n\n[% added %] records added\n[% updated %] records updated\n[% deleted %] records deleted\n[% skipped %] records skipped\n[% in_error %] records in error\n[% total %] total','email','default');
|
||||
}
|
||||
);
|
||||
say $out "Added OAI_HARVEST_REPORT letter";
|
||||
|
||||
},
|
||||
};
|
||||
|
|
@ -2626,3 +2626,26 @@ tables:
|
|||
- "Your hold on [% hold.biblio.title %] ([% hold.biblio.id %]) has been confirmed."
|
||||
- "You will be notified by the library when your item is available for pickup."
|
||||
- "Thank you!"
|
||||
|
||||
- module: catalogue
|
||||
code: OAI_HARVEST_REPORT
|
||||
branchcode: ""
|
||||
name: "OAI Harvest Report"
|
||||
is_html: 0
|
||||
title: "OAI Harvest report for [% servername %]"
|
||||
message_transport_type: email
|
||||
lang: default
|
||||
content:
|
||||
- "OAI Harvest report for [% servername %]:"
|
||||
- ""
|
||||
- "Endpoint: [% endpoint %]"
|
||||
- "Set: [% set %]"
|
||||
- "Data format: [% dataformat %]"
|
||||
- "Record type: [% recordtype %]"
|
||||
- ""
|
||||
- "[% added %] records added"
|
||||
- "[% updated %] records updated"
|
||||
- "[% deleted %] records deleted"
|
||||
- "[% skipped %] records skipped"
|
||||
- "[% in_error %] records in error"
|
||||
- "[% total %] total"
|
||||
|
|
|
|||
|
|
@ -4858,6 +4858,64 @@ CREATE TABLE `oai_sets_mappings` (
|
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `oaiservers`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `oaiservers`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `oaiservers` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique identifier assigned by Koha',
|
||||
`endpoint` varchar(255) NOT NULL COMMENT 'OAI endpoint (host + port + path)',
|
||||
`oai_set` varchar(255) DEFAULT NULL COMMENT 'OAI set to harvest',
|
||||
`servername` longtext NOT NULL COMMENT 'name given to the target by the library',
|
||||
`dataformat` enum('oai_dc','marc-xml', 'marcxml') NOT NULL DEFAULT 'oai_dc' COMMENT 'data format',
|
||||
`recordtype` enum('authority','biblio') NOT NULL DEFAULT 'biblio' COMMENT 'server contains bibliographic or authority records',
|
||||
`add_xslt` longtext DEFAULT NULL COMMENT 'zero or more paths to XSLT files to be processed on the search results',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
--
|
||||
-- Table structure for table `import_oaipmh_biblios`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `import_oaipmh_biblios`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `import_oaipmh_biblios` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique identifier assigned by Koha',
|
||||
`biblionumber` int(11) NOT NULL COMMENT 'unique identifier assigned to each koha record',
|
||||
`identifier` varchar(255) NOT NULL COMMENT 'OAI record identifier',
|
||||
`repository` varchar(255) NOT NULL COMMENT 'OAI repository',
|
||||
`recordtype` enum('authority','biblio') NOT NULL DEFAULT 'biblio' COMMENT 'is the record bibliographic or authority',
|
||||
`datestamp` varchar(255) DEFAULT NULL COMMENT 'OAI set to harvest',
|
||||
`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
KEY biblionumber (biblionumber),
|
||||
CONSTRAINT FK_import_oaipmh_biblios_1 FOREIGN KEY (biblionumber) REFERENCES biblio (biblionumber) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
--
|
||||
-- Table structure for table `import_oaipmh_authorities`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `import_oaipmh_authorities`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `import_oaipmh_authorities` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'unique identifier assigned by Koha',
|
||||
`authid` bigint(20) unsigned NOT NULL COMMENT 'unique identifier assigned to each koha record',
|
||||
`identifier` varchar(255) NOT NULL COMMENT 'OAI record identifier',
|
||||
`repository` varchar(255) NOT NULL COMMENT 'OAI repository',
|
||||
`recordtype` enum('authority','biblio') NOT NULL DEFAULT 'biblio' COMMENT 'is the record bibliographic or authority',
|
||||
`datestamp` varchar(255) DEFAULT NULL COMMENT 'OAI set to harvest',
|
||||
`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
KEY authid (authid),
|
||||
CONSTRAINT FK_import_oaipmh_authorities_1 FOREIGN KEY (authid) REFERENCES auth_header (authid) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
--
|
||||
-- Table structure for table `oauth_access_tokens`
|
||||
--
|
||||
|
|
|
|||
|
|
@ -449,6 +449,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `
|
|||
('OAI-PMH:AutoUpdateSetsEmbedItemData', '0', '', 'Embed item information when automatically updating OAI sets. Requires OAI-PMH:AutoUpdateSets syspref to be enabled', 'YesNo'),
|
||||
('OAI-PMH:ConfFile','',NULL,'If empty, Koha OAI Server operates in normal mode, otherwise it operates in extended mode.','File'),
|
||||
('OAI-PMH:DeletedRecord','persistent','Koha\'s deletedbiblio table will never be deleted (persistent), might be deleted (transient), or will never have any data in it (no)','transient|persistent|no','Choice'),
|
||||
('OAI-PMH:HarvestEmailReport','','','If set, a report email will be sent to this address after an OAI harvest','Free'),
|
||||
('OAI-PMH:MaxCount','50',NULL,'OAI-PMH maximum number of records by answer to ListRecords and ListIdentifiers queries','Integer'),
|
||||
('OnSiteCheckoutAutoCheck','0','','Enable/Do not enable onsite checkout by default if last checkout was an onsite checkout','YesNo'),
|
||||
('OnSiteCheckouts','0','','Enable/Disable the on-site checkouts feature','YesNo'),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
|
|||
( 3, 'manage_item_search_fields', 'Manage item search fields'),
|
||||
( 3, 'manage_search_engine_config', 'Manage search engine configuration'),
|
||||
( 3, 'manage_marc_overlay_rules', 'Manage MARC overlay rules configuration'),
|
||||
( 3, 'manage_search_targets', 'Manage Z39.50 and SRU server configuration'),
|
||||
( 3, 'manage_search_targets', 'Manage Z39.50 and SRU servers, OAI repositories configuration'),
|
||||
( 3, 'manage_didyoumean', 'Manage Did you mean? configuration'),
|
||||
( 3, 'manage_column_config', 'Manage column configuration'),
|
||||
( 3, 'manage_sms_providers', 'Manage SMS cellular providers'),
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@
|
|||
[% END %]
|
||||
[% IF ( CAN_user_parameters_manage_search_targets ) %]
|
||||
<li><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50/SRU servers</a></li>
|
||||
<li><a href="/cgi-bin/koha/admin/oaiservers.pl">OAI repositories</a></li>
|
||||
[% END %]
|
||||
[% IF ( CAN_user_parameters_manage_smtp_servers ) %]
|
||||
<li><a href="/cgi-bin/koha/admin/smtp_servers.pl">SMTP servers</a></li>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
[% USE Koha %]
|
||||
<!-- oai-admin-search.inc -->
|
||||
<div id="header_search" role="tablist">
|
||||
<div class="tab-content">
|
||||
<div id="oai_search" role="tabpanel" class="tab-pane active">
|
||||
<form action="/cgi-bin/koha/admin/oaiservers.pl" method="post">
|
||||
<div class="form-title">
|
||||
<label class="control-label">Search OAI repositories</label>
|
||||
</div>
|
||||
|
||||
<div class="form-content">
|
||||
<input class="head-searchbox form-control" type="text" name="searchfield" id="searchfield" value="[% searchfield | html %]" placeholder="OAI repository search" />
|
||||
</div>
|
||||
|
||||
<button type="submit"><i class="fa fa-arrow-right"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
[% IF ( CAN_user_circulate_circulate_remaining_permissions ) %]
|
||||
[% INCLUDE 'patron-search-box.inc' %]
|
||||
[% END %]
|
||||
[% IF ( CAN_user_catalogue ) %]
|
||||
[% INCLUDE 'catalogue-search-box.inc' %]
|
||||
[% END %]
|
||||
|
||||
</div><!-- /.tab-content -->
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li role="presentation" class="active">
|
||||
<a title="Search OAI repositories" href="#oai_search" aria-controls="z3950_search" role="tab" aria-expanded="true" data-toggle="tab" class="keep_text"><i class="fa fa-search"></i> <span class="tab-title">Search OAI repositories</span></a>
|
||||
</li>
|
||||
[% IF ( CAN_user_circulate_circulate_remaining_permissions ) %]
|
||||
<li role="presentation">
|
||||
<a title="Check out" href="#circ_search" aria-controls="circ_search" role="tab" data-toggle="tab" class="keep_text"><i class="fa fa-upload"></i> <span class="tab-title">Check out</span></a>
|
||||
</li>
|
||||
[% END %]
|
||||
[% IF ( CAN_user_catalogue ) %]
|
||||
<li role="presentation">
|
||||
<a title="Search catalog" href="#catalog_search" aria-controls="catalog_search" role="tab" data-toggle="tab" class="keep_text"><i class="fa fa-fw fa-search"></i> <span class="tab-title">Search catalog</span></a>
|
||||
</li>
|
||||
[% END %]
|
||||
</ul>
|
||||
</div><!-- /#header_search -->
|
||||
<!-- /oai-admin-search.inc -->
|
||||
|
|
@ -244,7 +244,7 @@
|
|||
<span class="permissioncode">([% name | html %])</span>
|
||||
[%- CASE 'manage_search_targets' -%]
|
||||
<span class="sub_permission manage_search_targets_subpermission">
|
||||
Manage Z39.50 and SRU server configuration
|
||||
Manage Z39.50 and SRU servers, OAI repositories configuration
|
||||
</span>
|
||||
<span class="permissioncode">([% name | html %])</span>
|
||||
[%- CASE 'manage_didyoumean' -%]
|
||||
|
|
|
|||
|
|
@ -261,6 +261,8 @@
|
|||
[% IF ( CAN_user_parameters_manage_search_targets ) %]
|
||||
<dt><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50/SRU servers</a></dt>
|
||||
<dd>Define which external servers to query for MARC data</dd>
|
||||
<dt><a href="/cgi-bin/koha/admin/oaiservers.pl">OAI repositories</a></dt>
|
||||
<dd>Define which OAI repositories to harvest data from</dd>
|
||||
[% END %]
|
||||
[% IF ( CAN_user_parameters_manage_smtp_servers ) %]
|
||||
<dt><a href="/cgi-bin/koha/admin/smtp_servers.pl">SMTP servers</a></dt>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,229 @@
|
|||
[% USE raw %]
|
||||
[% USE Asset %]
|
||||
[% SET footerjs = 1 %]
|
||||
[% INCLUDE 'doc-head-open.inc' %]
|
||||
|
||||
<title>
|
||||
[% IF op == 'edit' %]
|
||||
Modify OAI repository [% server.servername | html %] › [% END %]
|
||||
|
||||
[% IF op == 'add' %]
|
||||
New OAI repository › [% END %]
|
||||
|
||||
OAI repositories › Administration › Koha
|
||||
</title>
|
||||
[% INCLUDE 'doc-head-close.inc' %]
|
||||
</head>
|
||||
|
||||
<body id="admin_oaiservers" class="admin">
|
||||
[% WRAPPER 'header.inc' %]
|
||||
[% INCLUDE 'oai-admin-search.inc' %]
|
||||
[% END %]
|
||||
|
||||
[% WRAPPER 'sub-header.inc' %]
|
||||
[% WRAPPER breadcrumbs %]
|
||||
[% WRAPPER breadcrumb_item %]
|
||||
<a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
|
||||
[% END %]
|
||||
|
||||
[% IF op == 'edit' || op == 'add' %]
|
||||
[% WRAPPER breadcrumb_item %]
|
||||
<a href="/cgi-bin/koha/admin/oaiservers.pl">OAI repositories</a>
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% IF op == 'edit' %]
|
||||
[% WRAPPER breadcrumb_item bc_active= 1 %]
|
||||
<span>Modify OAI repository [% server.servername | html %]</span>
|
||||
[% END %]
|
||||
|
||||
[% ELSIF op == 'add' %]
|
||||
[% WRAPPER breadcrumb_item bc_active= 1 %]
|
||||
<span>New OAI repository</span>
|
||||
[% END %]
|
||||
|
||||
[% ELSE %]
|
||||
[% WRAPPER breadcrumb_item bc_active= 1 %]
|
||||
<span>OAI repositories</span>
|
||||
[% END %]
|
||||
[% END %]
|
||||
[% END #/ WRAPPER breadcrumbs %]
|
||||
[% END #/ WRAPPER sub-header.inc %]
|
||||
|
||||
<div class="main container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-10 col-sm-push-2">
|
||||
<main>
|
||||
|
||||
[% IF msg_deleted %]
|
||||
<div class="dialog alert">OAI repository deleted ([% msg_add | html %])</div>
|
||||
[% ELSIF msg_updated %]
|
||||
<div class="dialog message">OAI repository updated ([% msg_add | html %])</div>
|
||||
[% ELSIF msg_added %]
|
||||
<div class="dialog message">OAI repository added ([% msg_add | html %])</div>
|
||||
[% ELSIF msg_notfound %]
|
||||
<div class="dialog alert">Error: Server with ID [% msg_add | html %] not found</div>
|
||||
[% END %]
|
||||
|
||||
[% IF ( add_form ) %]
|
||||
<form action="[% script_name | html %]" name="Aform" method="post" id="serverentry">
|
||||
<input type="hidden" name="op" value="add_validated" />
|
||||
[% IF op == 'edit' %]
|
||||
<h1>Modify OAI repository</h1>
|
||||
<input type="hidden" name="id" value="[% server.id | html %]" />
|
||||
[% ELSE %]
|
||||
<h1>New OAI repository</h1>
|
||||
[% END %]
|
||||
<fieldset class="rows">
|
||||
<ol>
|
||||
<li><label for="name" class="required">Repository name: </label>
|
||||
[% IF server.servername %]
|
||||
<input type="text" name="servername" id="servername" size="65" maxlength="100" value="[% server.servername | html %]" required="required" />
|
||||
[% ELSE %]
|
||||
<input type="text" name="servername" id="servername" class="focus" size="65" maxlength="100" value="[% server.servername | html %]" required="required" />
|
||||
[% END %]
|
||||
<span class="required">Required</span>
|
||||
</li>
|
||||
|
||||
<li><label for="endpoint" class="required">Endpoint: </label> <input type="text" name="endpoint" id="endpoint" size="30" value="[% server.endpoint | html %]" required="required" /> <span class="required">Required</span>
|
||||
</li>
|
||||
<li><label for="oai_set">Set: </label> <input type="text" name="oai_set" id="oai_set" value="[% server.oai_set | html %]" />
|
||||
</li>
|
||||
<li>
|
||||
<label for="dataformat">Data format: </label>
|
||||
<select name="dataformat" id="dataformat">
|
||||
<option value="oai_dc">Dublin Core (oai_dc)</option>
|
||||
<option value="marc-xml">Marcxml (marc-xml)</option>
|
||||
<option value="marcxml">Marcxml (marcxml)</option>
|
||||
</select>
|
||||
<div class="hint">OAI can send records in various formats. Choose one.</div>
|
||||
</li>
|
||||
|
||||
<li><label for="recordtype">Record type: </label>
|
||||
<select name="recordtype" id="recordtype">
|
||||
<option value="biblio">Bibliographic</option>
|
||||
<option value="authority">Authority</option>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
<label for="add_xslt">XSLT file for transforming results: </label>
|
||||
<input type="text" name="add_xslt" id="add_xslt" size="100" placeholder="[% xslt_path | html %]" value="[% server.add_xslt | html %]"/>
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="action"><input type="submit" class="btn btn-primary" value="Save" /> <a class="cancel" href="/cgi-bin/koha/admin/oaiservers.pl">Cancel</a></fieldset>
|
||||
</form>
|
||||
[% END %]
|
||||
|
||||
[% IF op == 'list' %]
|
||||
<div id="toolbar" class="btn-toolbar">
|
||||
<a id="newserver" class="btn btn-default" href="/cgi-bin/koha/admin/oaiservers.pl?op=add"><i class="fa fa-plus"></i> New OAI repository</a>
|
||||
</div>
|
||||
<h1>OAI repositories administration</h1>
|
||||
[% IF id %]
|
||||
You searched for record [% id | html %]
|
||||
[% ELSIF searchfield %]
|
||||
You searched for [% searchfield | html %]
|
||||
[% END %]
|
||||
|
||||
<div class="page-section">
|
||||
<table id="serverst">
|
||||
|
||||
<thead><tr><th>Id</th><th>Repository name</th><th>Endpoint</th><th>Set</th><th>Data format</th><th>Record type</th><th class="noExport">Actions</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
[% FOREACH loo IN loop %]
|
||||
<tr>
|
||||
<td>[% loo.id | html %]</td>
|
||||
<td><a href="/cgi-bin/koha/admin/oaiservers.pl?op=edit&id=[% loo.id | uri %]">[% loo.servername | html %]</a></td><td>[% loo.endpoint | html %]</td><td>[% loo.oai_set | html %]</td>
|
||||
<td>[% loo.dataformat | html %]</td>
|
||||
<td>[% IF ( loo.recordtype == 'biblio' ) %]
|
||||
<span>Bibliographic</span>
|
||||
[% ELSIF ( loo.recordtype == 'authority' ) %]
|
||||
<span>Authority</span>
|
||||
[% END %]
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group dropup">
|
||||
<a class="btn btn-default btn-xs dropdown-toggle" id="reportactions[% savedreport.id | html %]" role="button" data-toggle="dropdown" href="#">
|
||||
Actions <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="reportactions[% savedreport.id | html %]">
|
||||
<li><a href="/cgi-bin/koha/admin/oaiservers.pl?op=edit&id=[% loo.id | uri %]"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit</a></li>
|
||||
<li><a href="/cgi-bin/koha/admin/oaiservers.pl?op=add&id=[% loo.id | uri %]"><i class="fa fa-copy"></i> Copy</a></li>
|
||||
<li><a href="/cgi-bin/koha/admin/oaiservers.pl?op=delete_confirmed&id=[% loo.id | uri %]" class="delete" data-servername="[% loo.servername | html %]"><i class="fa fa-trash-can"></i> Delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</tbody>
|
||||
</table>
|
||||
</div> <!-- /.page-section -->
|
||||
[% END %]
|
||||
|
||||
</main>
|
||||
</div> <!-- /.col-sm-10.col-sm-push-2 -->
|
||||
|
||||
<div class="col-sm-2 col-sm-pull-10">
|
||||
<aside>
|
||||
[% INCLUDE 'admin-menu.inc' %]
|
||||
</aside>
|
||||
</div> <!-- /.col-sm-2.col-sm-pull-10 -->
|
||||
</div> <!-- /.row -->
|
||||
|
||||
[% MACRO jsinclude BLOCK %]
|
||||
[% Asset.js("js/admin-menu.js") | $raw %]
|
||||
[% IF op == 'list' %]
|
||||
[% INCLUDE 'datatables.inc' %]
|
||||
[% END %]
|
||||
|
||||
<script>
|
||||
[% IF ( add_form ) %]
|
||||
$(document).ready(function(){
|
||||
// Update selects for dataformat and recordtype
|
||||
[% IF server %]
|
||||
$("#dataformat").val('[% server.dataformat | html %]');
|
||||
$("#recordtype").val('[% server.recordtype | html %]');
|
||||
[% END %]
|
||||
$( "#serverentry" ).validate({
|
||||
rules: {
|
||||
servername: { required: true },
|
||||
host: { required: true },
|
||||
port: {
|
||||
number: true
|
||||
},
|
||||
rank: { number: true },
|
||||
}
|
||||
});
|
||||
$("#serverentry").submit(function( event ) {
|
||||
// enable recordtype to include field in post
|
||||
$('#recordtype').prop('disabled',false);
|
||||
});
|
||||
$("#servername").on("blur",function(){
|
||||
toUC(this);
|
||||
});
|
||||
});
|
||||
[% ELSE %]
|
||||
$(document).ready(function() {
|
||||
$("#serverst").dataTable($.extend(true, {}, dataTablesDefaults, {
|
||||
"aoColumnDefs": [
|
||||
{ "aTargets": [-1], "bSortable": false, "bSearchable": false },
|
||||
],
|
||||
"sPaginationType": "full"
|
||||
}));
|
||||
$(".delete").on("click",function(e){
|
||||
var servername = $(this).data("servername");
|
||||
if( confirm( _("Are you sure you want to delete repository %s?").format(servername) ) ) {
|
||||
return true;
|
||||
} else {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
[% END %]
|
||||
</script>
|
||||
[% END %]
|
||||
[% INCLUDE 'intranet-bottom.inc' %]
|
||||
|
|
@ -91,6 +91,11 @@ Web services:
|
|||
transient: might be emptied or truncated at some point (transient)
|
||||
no: will never have any data in it (no)
|
||||
- "."
|
||||
-
|
||||
- If set, a report email will be sent to this address after an OAI harvest
|
||||
- pref: "OAI-PMH:HarvestEmailReport"
|
||||
class: Text
|
||||
|
||||
ILS-DI:
|
||||
-
|
||||
- pref: ILS-DI
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:dcterms="http://purl.org/dc/terms/1.1"
|
||||
xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/
|
||||
http://www.openarchives.org/OAI/2.0/oai_dc.xsd"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns="http://www.loc.gov/MARC21/slim" exclude-result-prefixes="dc dcterms oai_dc">
|
||||
|
||||
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd" >
|
||||
<xsl:apply-templates />
|
||||
</collection>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="oai_dc:dc">
|
||||
<record>
|
||||
|
||||
<xsl:variable name="FamilyName" select="dc:FamilyName"/>
|
||||
<xsl:variable name="GivenName" select="dc:GivenName"/>
|
||||
|
||||
<datafield tag="100" ind1="0" ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="concat($FamilyName,', ',$GivenName)"/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
|
||||
</record>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:dcterms="http://purl.org/dc/terms/1.1"
|
||||
xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/
|
||||
http://www.openarchives.org/OAI/2.0/oai_dc.xsd"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns="http://www.loc.gov/MARC21/slim" exclude-result-prefixes="dc dcterms oai_dc">
|
||||
|
||||
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd" >
|
||||
<xsl:apply-templates />
|
||||
</collection>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="oai_dc:dc">
|
||||
<record>
|
||||
|
||||
<xsl:for-each select="dc:FamilyName">
|
||||
<datafield tag="200" ind1="0" ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="dc:GivenName">
|
||||
<datafield tag="200" ind1="0" ind2=" ">
|
||||
<subfield code="b">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
</record>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -0,0 +1,367 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:dcterms="http://purl.org/dc/terms/1.1"
|
||||
xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/
|
||||
http://www.openarchives.org/OAI/2.0/oai_dc.xsd"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns="http://www.loc.gov/MARC21/slim" exclude-result-prefixes="dc dcterms oai_dc">
|
||||
|
||||
<xsl:import href="MARC21slimUtils.xsl"/>
|
||||
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
|
||||
|
||||
|
||||
<xsl:template match="/">
|
||||
<collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd" >
|
||||
<xsl:apply-templates />
|
||||
</collection>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="OAI-PMH">
|
||||
<xsl:for-each select = "ListRecords/record/metadata/oai_dc:dc">
|
||||
<xsl:apply-templates />
|
||||
</xsl:for-each>
|
||||
<xsl:for-each select = "GetRecord/record/metadata/oai_dc:dc">
|
||||
<xsl:apply-templates />
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="text()" />
|
||||
<xsl:template match="oai_dc:dc">
|
||||
<record>
|
||||
<xsl:element name="leader">
|
||||
<xsl:variable name="type" select="dc:type"/>
|
||||
<xsl:variable name="leader06">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$type='collection'">p</xsl:when>
|
||||
<xsl:when test="$type='dataset'">m</xsl:when>
|
||||
<xsl:when test="$type='event'">r</xsl:when>
|
||||
<xsl:when test="$type='image'">k</xsl:when>
|
||||
<xsl:when test="$type='interactive resource'">m</xsl:when>
|
||||
<xsl:when test="$type='service'">m</xsl:when>
|
||||
<xsl:when test="$type='software'">m</xsl:when>
|
||||
<xsl:when test="$type='sound'">i</xsl:when>
|
||||
<xsl:when test="$type='text'">a</xsl:when>
|
||||
<xsl:otherwise>a</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="leader07">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$type='collection'">c</xsl:when>
|
||||
<xsl:otherwise>m</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:value-of select="concat(' ',$leader06,$leader07,' 3u ')"/>
|
||||
</xsl:element>
|
||||
|
||||
<datafield tag="042" ind1=" " ind2=" ">
|
||||
<subfield code="a">dc</subfield>
|
||||
</datafield>
|
||||
|
||||
|
||||
|
||||
<xsl:for-each select="dc:creator">
|
||||
<xsl:choose>
|
||||
<xsl:when test="(.!='') and (position()=1)">
|
||||
<xsl:call-template name="persname_template">
|
||||
<xsl:with-param name="string" select="." />
|
||||
<xsl:with-param name="field" select="'100'" />
|
||||
<xsl:with-param name="ind1" select = "'1'" />
|
||||
<xsl:with-param name="ind2" select = "'0'" />
|
||||
<xsl:with-param name="type" select="'author'" />
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:if test=".!=''">
|
||||
<xsl:call-template name="persname_template">
|
||||
<xsl:with-param name="string" select="." />
|
||||
<xsl:with-param name="field" select="'700'" />
|
||||
<xsl:with-param name="ind1" select = "'1'" />
|
||||
<xsl:with-param name="ind2" select = "'0'" />
|
||||
<xsl:with-param name="type" select="'author'" />
|
||||
</xsl:call-template>
|
||||
</xsl:if>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:title[1]">
|
||||
<datafield tag="245" ind1="0" ind2="0">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="dc:title[position()>1]">
|
||||
<xsl:if test=".!=''">
|
||||
<datafield tag="246" ind1="3" ind2="3">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="dc:publisher">
|
||||
<xsl:if test="translate(dc:publisher/.,'.,:;','')!=''">
|
||||
<datafield tag="260" ind1=" " ind2=" ">
|
||||
<xsl:choose>
|
||||
<xsl:when test="dc:date">
|
||||
<subfield code="b"><xsl:value-of select="dc:publisher[1]"/>, </subfield>
|
||||
<xsl:if test="translate(dc:date[1]/., '.,:;','')!=''">
|
||||
<subfield code="c"><xsl:value-of select="dc:date[1]" />.</subfield>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<subfield code="b"><xsl:value-of select="dc:publisher[1]"/>.</subfield>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</datafield>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:if test="translate(dc:date[1],'.,:;','')!=''">
|
||||
<datafield tag="260" ind1=" " ind2=" ">
|
||||
<subfield code="c"><xsl:value-of select="dc:date[1]" />.</subfield>
|
||||
</datafield>
|
||||
</xsl:if>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
|
||||
<xsl:for-each select="dc:coverage">
|
||||
<xsl:choose>
|
||||
<xsl:when test="translate(., '0123456789-.?','')=''">
|
||||
<!--Likely;this is a date-->
|
||||
<datafield tag="500" ind1=" " ind2=" ">
|
||||
<subfield code="a"><xsl:value-of select="."/></subfield>
|
||||
</datafield>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!--likely a geographic subject, we will print this later-->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="dc:identifier">
|
||||
<xsl:if test="position()!=last()">
|
||||
<datafield tag="500" ind1=" " ind2=" ">
|
||||
<subfield code="a"><xsl:value-of select="." /></subfield>
|
||||
</datafield>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="dc:description">
|
||||
<datafield tag="520" ind1=" " ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="normalize-space(.)"/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:rights">
|
||||
<datafield tag="540" ind1=" " ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:language">
|
||||
<datafield tag="546" ind1=" " ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
|
||||
<xsl:for-each select="dc:subject">
|
||||
<datafield tag="690" ind1=" " ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="dc:coverage">
|
||||
<xsl:choose>
|
||||
<xsl:when test="translate(., '0123456789-.?','')=''">
|
||||
<!--Likely; this is a date-->
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!--likely a geographic subject-->
|
||||
<datafield tag="691" ind1=" " ind2=" ">
|
||||
<subfield code="a"><xsl:value-of select="." /></subfield>
|
||||
</datafield>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:type">
|
||||
<datafield tag="655" ind1="7" ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
<subfield code="2">local</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
|
||||
<xsl:for-each select="dc:contributer">
|
||||
<xsl:call-template name="persname_template">
|
||||
<xsl:with-param name="string" select="." />
|
||||
<xsl:with-param name="field" select="'100'" />
|
||||
<xsl:with-param name="ind1" select = "'1'" />
|
||||
<xsl:with-param name="ind2" select = "'0'" />
|
||||
<xsl:with-param name="type" select="'contributor'" />
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="dc:source">
|
||||
<datafield tag="786" ind1="0" ind2=" ">
|
||||
<subfield code="n">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="dc:relation">
|
||||
<datafield tag="787" ind1="0" ind2=" ">
|
||||
<subfield code="n">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:if test="dc:identifier">
|
||||
<datafield tag="856" ind1="4" ind2="1">
|
||||
<subfield code="u"><xsl:value-of select="dc:identifier[last()]" /></subfield>
|
||||
<subfield code="z">Connect to this object online.</subfield>
|
||||
</datafield>
|
||||
</xsl:if>
|
||||
</record>
|
||||
|
||||
</xsl:template>
|
||||
<xsl:template name="persname_template">
|
||||
<xsl:param name="string" />
|
||||
<xsl:param name="field" />
|
||||
<xsl:param name="ind1" />
|
||||
<xsl:param name="ind2" />
|
||||
<xsl:param name="type" />
|
||||
<datafield>
|
||||
<xsl:attribute name="tag">
|
||||
<xsl:value-of select="$field" />
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="ind1">
|
||||
<xsl:value-of select="$ind1" />
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="ind2">
|
||||
<xsl:value-of select="$ind2" />
|
||||
</xsl:attribute>
|
||||
|
||||
<!-- Sample input: Brightman, Samuel C. (Samuel Charles), 1911-1992 -->
|
||||
<!-- Sample output: $aBrightman, Samuel C. $q(Samuel Charles), $d1911-. -->
|
||||
<!-- will handle names with dashes e.g. Bourke-White, Margaret -->
|
||||
|
||||
<!-- CAPTURE PRIMARY NAME BY LOOKING FOR A PAREN OR A DASH OR NEITHER -->
|
||||
<xsl:choose>
|
||||
<!-- IF A PAREN, STOP AT AN OPENING PAREN -->
|
||||
<xsl:when test="contains($string, '(')!=0">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="substring-before($string, '(')" />
|
||||
</subfield>
|
||||
</xsl:when>
|
||||
<!-- IF A DASH, CHECK IF IT'S A DATE OR PART OF THE NAME -->
|
||||
<xsl:when test="contains($string, '-')!=0">
|
||||
<xsl:variable name="name_1" select="substring-before($string, '-')" />
|
||||
<xsl:choose>
|
||||
<!-- IF IT'S A DATE REMOVE IT -->
|
||||
<xsl:when test="translate(substring($name_1, (string-length($name_1)), 1), '0123456789', '9999999999') = '9'">
|
||||
<xsl:variable name="name" select="substring($name_1, 1, (string-length($name_1)-6))" />
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="$name" />
|
||||
</subfield>
|
||||
</xsl:when>
|
||||
<!-- IF IT'S NOT A DATE, CHECK WHETHER THERE IS A DATE LATER -->
|
||||
<xsl:otherwise>
|
||||
<xsl:variable name="remainder" select="substring-after($string, '-')" />
|
||||
<xsl:choose>
|
||||
<!-- IF THERE'S A DASH, ASSUME IT'S A DATE AND REMOVE IT -->
|
||||
<xsl:when test="contains($remainder, '-')!=0">
|
||||
<xsl:variable name="tmp" select="substring-before($remainder, '-')" />
|
||||
<xsl:variable name="name_2" select="substring($tmp, 1, (string-length($tmp)-6))" />
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="$name_1" />-<xsl:value-of select="$name_2" />
|
||||
</subfield>
|
||||
</xsl:when>
|
||||
<!-- IF THERE'S NO DASH IN THE REMAINDER, OUTPUT IT -->
|
||||
<xsl:otherwise>
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="$string" />
|
||||
</subfield>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<!-- NO DASHES, NO PARENS, JUST OUTPUT THE NAME -->
|
||||
<xsl:otherwise>
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="$string" />
|
||||
</subfield>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
|
||||
<!-- CAPTURE SECONDARY NAME IN PARENS FOR SUBFIELD Q -->
|
||||
<xsl:if test="contains($string, '(')!=0">
|
||||
<xsl:variable name="subq_tmp" select="substring-after($string, '(')" />
|
||||
<xsl:variable name="subq" select="substring-before($subq_tmp, ')')" />
|
||||
<subfield code="q">
|
||||
(<xsl:value-of select="$subq" />)
|
||||
</subfield>
|
||||
</xsl:if>
|
||||
|
||||
<!-- CAPTURE DATE FOR SUBFIELD D, ASSUME DATE IS LAST ITEM IN FIELD -->
|
||||
<!-- Note: does not work if name has a dash in it -->
|
||||
<xsl:if test="contains($string, '-')!=0">
|
||||
<xsl:variable name="date_tmp" select="substring-before($string, '-')" />
|
||||
<xsl:variable name="remainder" select="substring-after($string, '-')" />
|
||||
<xsl:choose>
|
||||
<!-- CHECK SECOND HALF FOR ANOTHER DASH; IF PRESENT, ASSUME THAT IS DATE -->
|
||||
<xsl:when test="contains($remainder, '-')!=0">
|
||||
<xsl:variable name="tmp" select="substring-before($remainder, '-')" />
|
||||
<xsl:variable name="date_1" select="substring($remainder, (string-length($tmp)-3))" />
|
||||
<!-- CHECK WHETHER IT HAS A NUMBER BEFORE IT AND IF SO, OUTPUT IT AS DATE -->
|
||||
<xsl:if test="translate(substring($date_1, 1, 1), '0123456789', '9999999999') = '9'">
|
||||
<subfield code="d">
|
||||
<xsl:value-of select="$date_1" />.
|
||||
</subfield>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
<!-- OTHERWISE THIS IS THE ONLY DASH SO TAKE IT -->
|
||||
<xsl:otherwise>
|
||||
<xsl:variable name="date_2" select="substring($string, (string-length($date_tmp)-3))" />
|
||||
<!-- CHECK WHETHER IT HAS A NUMBER BEFORE IT AND IF SO, OUTPUT IT AS DATE -->
|
||||
<xsl:if test="translate(substring($date_2, 1, 1), '0123456789', '9999999999') = '9'">
|
||||
<subfield code="d">
|
||||
<xsl:value-of select="$date_2" />.
|
||||
</subfield>
|
||||
</xsl:if>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:if>
|
||||
<subfield code="e"><xsl:value-of select="$type" /></subfield>
|
||||
</datafield>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:dcterms="http://purl.org/dc/terms/1.1"
|
||||
xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/
|
||||
http://www.openarchives.org/OAI/2.0/oai_dc.xsd"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns="http://www.loc.gov/MARC21/slim" exclude-result-prefixes="dc dcterms oai_dc">
|
||||
|
||||
<xsl:import href="MARC21slimUtils.xsl"/>
|
||||
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
|
||||
|
||||
|
||||
<xsl:template match="/">
|
||||
<collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd" >
|
||||
<xsl:apply-templates />
|
||||
</collection>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="OAI-PMH">
|
||||
<xsl:for-each select = "ListRecords/record/metadata/oai_dc:dc">
|
||||
<xsl:apply-templates />
|
||||
</xsl:for-each>
|
||||
<xsl:for-each select = "GetRecord/record/metadata/oai_dc:dc">
|
||||
<xsl:apply-templates />
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="text()" />
|
||||
<xsl:template match="oai_dc:dc">
|
||||
<record>
|
||||
|
||||
<xsl:for-each select="dc:creator">
|
||||
<xsl:call-template name="persname_template">
|
||||
<xsl:with-param name="string" select="." />
|
||||
<xsl:with-param name="field" select="'700'" />
|
||||
<xsl:with-param name="ind1" select = "'1'" />
|
||||
<xsl:with-param name="ind2" select = "'0'" />
|
||||
<xsl:with-param name="type" select="'author'" />
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:title[1]">
|
||||
<datafield tag="200" ind1="0" ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="dc:title[position()>1]">
|
||||
<xsl:if test=".!=''">
|
||||
<datafield tag="532" ind1="3" ind2="0">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="dc:publisher">
|
||||
<xsl:if test="translate(dc:publisher/.,'.,:;','')!=''">
|
||||
<datafield tag="214" ind1=" " ind2=" ">
|
||||
<xsl:choose>
|
||||
<xsl:when test="dc:date">
|
||||
<subfield code="c"><xsl:value-of select="dc:publisher[1]"/>, </subfield>
|
||||
<xsl:if test="translate(dc:date[1]/., '.,:;','')!=''">
|
||||
<subfield code="d"><xsl:value-of select="dc:date[1]" />.</subfield>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<subfield code="c"><xsl:value-of select="dc:publisher[1]"/>.</subfield>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</datafield>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:if test="translate(dc:date[1],'.,:;','')!=''">
|
||||
<datafield tag="214" ind1=" " ind2=" ">
|
||||
<subfield code="d"><xsl:value-of select="dc:date[1]" />.</subfield>
|
||||
</datafield>
|
||||
</xsl:if>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:contributor">
|
||||
<datafield tag="701" ind1=" " ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:coverage">
|
||||
<xsl:choose>
|
||||
<xsl:when test="translate(., '0123456789-.?','')=''">
|
||||
<!--Likely;this is a date-->
|
||||
<datafield tag="215" ind1=" " ind2=" ">
|
||||
<subfield code="a"><xsl:value-of select="."/></subfield>
|
||||
</datafield>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!--likely a geographic subject, we will print this later-->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:description">
|
||||
<datafield tag="330" ind1=" " ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="normalize-space(.)"/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<!-- no match -->
|
||||
<xsl:for-each select="dc:rights">
|
||||
<datafield tag="371" ind1=" " ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:language">
|
||||
<datafield tag="101" ind1=" " ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:subject">
|
||||
<datafield tag="610" ind1=" " ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<!-- Resource type will most likely need a specific instance-based mapping -->
|
||||
<!--
|
||||
<xsl:for-each select="dc:type">
|
||||
<datafield tag="099" ind1=" " ind2=" ">
|
||||
<subfield code="t">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
-->
|
||||
|
||||
|
||||
<!-- no match -->
|
||||
<xsl:for-each select="dc:coverage">
|
||||
<xsl:choose>
|
||||
<xsl:when test="translate(., '0123456789-.?','')=''">
|
||||
<!--Likely; this is a date-->
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!--likely a geographic subject-->
|
||||
<datafield tag="691" ind1=" " ind2=" ">
|
||||
<subfield code="a"><xsl:value-of select="." /></subfield>
|
||||
</datafield>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<!-- no match -->
|
||||
<xsl:for-each select="dc:type">
|
||||
<datafield tag="655" ind1="7" ind2=" ">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
<subfield code="2">local</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
|
||||
<xsl:for-each select="dc:contributer">
|
||||
<xsl:call-template name="persname_template">
|
||||
<xsl:with-param name="string" select="." />
|
||||
<xsl:with-param name="field" select="'702'" />
|
||||
<xsl:with-param name="ind1" select = "'1'" />
|
||||
<xsl:with-param name="ind2" select = "'0'" />
|
||||
<xsl:with-param name="type" select="'contributor'" />
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- no match -->
|
||||
<xsl:for-each select="dc:source">
|
||||
<datafield tag="786" ind1="0" ind2=" ">
|
||||
<subfield code="n">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- TODO: 455 456 470 488-->
|
||||
<xsl:for-each select="dc:relation">
|
||||
<datafield tag="488" ind1="0" ind2=" ">
|
||||
<subfield code="e">
|
||||
<xsl:value-of select="."/>
|
||||
</subfield>
|
||||
</datafield>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:if test="dc:identifier">
|
||||
<datafield tag="856" ind1="4" ind2="1">
|
||||
<subfield code="u"><xsl:value-of select="dc:identifier[last()]" /></subfield>
|
||||
<subfield code="z">Connect to this object online.</subfield>
|
||||
</datafield>
|
||||
</xsl:if>
|
||||
</record>
|
||||
|
||||
</xsl:template>
|
||||
<xsl:template name="persname_template">
|
||||
<xsl:param name="string" />
|
||||
<xsl:param name="field" />
|
||||
<xsl:param name="ind1" />
|
||||
<xsl:param name="ind2" />
|
||||
<xsl:param name="type" />
|
||||
<datafield>
|
||||
<xsl:attribute name="tag">
|
||||
<xsl:value-of select="$field" />
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="ind1">
|
||||
<xsl:value-of select="$ind1" />
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="ind2">
|
||||
<xsl:value-of select="$ind2" />
|
||||
</xsl:attribute>
|
||||
|
||||
<!-- Sample input: Brightman, Samuel C. (Samuel Charles), 1911-1992 -->
|
||||
<!-- Sample output: $aBrightman, Samuel C. $q(Samuel Charles), $d1911-. -->
|
||||
<!-- will handle names with dashes e.g. Bourke-White, Margaret -->
|
||||
|
||||
<!-- CAPTURE PRIMARY NAME BY LOOKING FOR A PAREN OR A DASH OR NEITHER -->
|
||||
<xsl:choose>
|
||||
<!-- IF A PAREN, STOP AT AN OPENING PAREN -->
|
||||
<xsl:when test="contains($string, '(')!=0">
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="substring-before($string, '(')" />
|
||||
</subfield>
|
||||
</xsl:when>
|
||||
<!-- IF A DASH, CHECK IF IT'S A DATE OR PART OF THE NAME -->
|
||||
<xsl:when test="contains($string, '-')!=0">
|
||||
<xsl:variable name="name_1" select="substring-before($string, '-')" />
|
||||
<xsl:choose>
|
||||
<!-- IF IT'S A DATE REMOVE IT -->
|
||||
<xsl:when test="translate(substring($name_1, (string-length($name_1)), 1), '0123456789', '9999999999') = '9'">
|
||||
<xsl:variable name="name" select="substring($name_1, 1, (string-length($name_1)-6))" />
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="$name" />
|
||||
</subfield>
|
||||
</xsl:when>
|
||||
<!-- IF IT'S NOT A DATE, CHECK WHETHER THERE IS A DATE LATER -->
|
||||
<xsl:otherwise>
|
||||
<xsl:variable name="remainder" select="substring-after($string, '-')" />
|
||||
<xsl:choose>
|
||||
<!-- IF THERE'S A DASH, ASSUME IT'S A DATE AND REMOVE IT -->
|
||||
<xsl:when test="contains($remainder, '-')!=0">
|
||||
<xsl:variable name="tmp" select="substring-before($remainder, '-')" />
|
||||
<xsl:variable name="name_2" select="substring($tmp, 1, (string-length($tmp)-6))" />
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="$name_1" />-<xsl:value-of select="$name_2" />
|
||||
</subfield>
|
||||
</xsl:when>
|
||||
<!-- IF THERE'S NO DASH IN THE REMAINDER, OUTPUT IT -->
|
||||
<xsl:otherwise>
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="$string" />
|
||||
</subfield>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<!-- NO DASHES, NO PARENS, JUST OUTPUT THE NAME -->
|
||||
<xsl:otherwise>
|
||||
<subfield code="a">
|
||||
<xsl:value-of select="$string" />
|
||||
</subfield>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
|
||||
<!-- CAPTURE SECONDARY NAME IN PARENS FOR SUBFIELD Q -->
|
||||
<xsl:if test="contains($string, '(')!=0">
|
||||
<xsl:variable name="subq_tmp" select="substring-after($string, '(')" />
|
||||
<xsl:variable name="subq" select="substring-before($subq_tmp, ')')" />
|
||||
<subfield code="q">
|
||||
(<xsl:value-of select="$subq" />)
|
||||
</subfield>
|
||||
</xsl:if>
|
||||
|
||||
<!-- CAPTURE DATE FOR SUBFIELD D, ASSUME DATE IS LAST ITEM IN FIELD -->
|
||||
<!-- Note: does not work if name has a dash in it -->
|
||||
<xsl:if test="contains($string, '-')!=0">
|
||||
<xsl:variable name="date_tmp" select="substring-before($string, '-')" />
|
||||
<xsl:variable name="remainder" select="substring-after($string, '-')" />
|
||||
<xsl:choose>
|
||||
<!-- CHECK SECOND HALF FOR ANOTHER DASH; IF PRESENT, ASSUME THAT IS DATE -->
|
||||
<xsl:when test="contains($remainder, '-')!=0">
|
||||
<xsl:variable name="tmp" select="substring-before($remainder, '-')" />
|
||||
<xsl:variable name="date_1" select="substring($remainder, (string-length($tmp)-3))" />
|
||||
<!-- CHECK WHETHER IT HAS A NUMBER BEFORE IT AND IF SO, OUTPUT IT AS DATE -->
|
||||
<xsl:if test="translate(substring($date_1, 1, 1), '0123456789', '9999999999') = '9'">
|
||||
<subfield code="d">
|
||||
<xsl:value-of select="$date_1" />.
|
||||
</subfield>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
<!-- OTHERWISE THIS IS THE ONLY DASH SO TAKE IT -->
|
||||
<xsl:otherwise>
|
||||
<xsl:variable name="date_2" select="substring($string, (string-length($date_tmp)-3))" />
|
||||
<!-- CHECK WHETHER IT HAS A NUMBER BEFORE IT AND IF SO, OUTPUT IT AS DATE -->
|
||||
<xsl:if test="translate(substring($date_2, 1, 1), '0123456789', '9999999999') = '9'">
|
||||
<subfield code="d">
|
||||
<xsl:value-of select="$date_2" />.
|
||||
</subfield>
|
||||
</xsl:if>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:if>
|
||||
<subfield code="e"><xsl:value-of select="$type" /></subfield>
|
||||
</datafield>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:marc="http://www.loc.gov/MARC21/slim">
|
||||
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
|
||||
|
||||
<!-- keep comments -->
|
||||
<xsl:template match="*[name()='metadata']">
|
||||
<xsl:apply-templates />
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="*">
|
||||
<!-- remove element prefix -->
|
||||
<xsl:element name="{local-name()}">
|
||||
<!-- process attributes -->
|
||||
<xsl:for-each select="@*">
|
||||
<!-- remove attribute prefix -->
|
||||
<xsl:attribute name="{local-name()}">
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:attribute>
|
||||
</xsl:for-each>
|
||||
<xsl:apply-templates/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
#!/usr/bin/perl
|
||||
#
|
||||
# Copyright 2023 BibLibre
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
use utf8;
|
||||
|
||||
use Getopt::Long qw( GetOptions );
|
||||
use Koha::Script -cron;
|
||||
use Koha::OAI::Client::Harvester;
|
||||
use Koha::OaiServers;
|
||||
use C4::Log qw( cronlogaction );
|
||||
use Try::Tiny qw( catch try );
|
||||
|
||||
my $command_line_options = join( " ", @ARGV );
|
||||
|
||||
my ( $help, $verbose, $id, $days, $list, $force );
|
||||
|
||||
GetOptions(
|
||||
'h|help' => \$help,
|
||||
'v|verbose' => \$verbose,
|
||||
'r|repository:i' => \$id,
|
||||
'd|days:i' => \$days,
|
||||
'l|list' => \$list,
|
||||
'f|force' => \$force,
|
||||
);
|
||||
my $usage = << 'ENDUSAGE';
|
||||
|
||||
This script starts an OAI Harvest
|
||||
|
||||
This script has the following parameters :
|
||||
-h --help: this message
|
||||
-v --verbose
|
||||
-r --repository: id of the OAI repository
|
||||
-d --days: number of days to harvest from (optional)
|
||||
-l --list: list the OAI repositories
|
||||
-f --force: force harvesting (ignore records datestamps)
|
||||
|
||||
ENDUSAGE
|
||||
|
||||
if ($help) {
|
||||
print $usage;
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($list) {
|
||||
my $servers = Koha::OaiServers->search( {}, { order_by => { -asc => 'id' } } )->unblessed;
|
||||
print "The following repositories are available: \n\n";
|
||||
foreach my $server (@$servers) {
|
||||
print $server->{'id'} . ": "
|
||||
. $server->{'servername'}
|
||||
. ", endpoint: "
|
||||
. $server->{'endpoint'}
|
||||
. ", set: "
|
||||
. $server->{'oai_set'}
|
||||
. ", recordtype: "
|
||||
. $server->{'recordtype'} . "\n";
|
||||
}
|
||||
print "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( !$id ) {
|
||||
print "The repository parameter is mandatory.\n";
|
||||
print $usage . "\n";
|
||||
}
|
||||
|
||||
my $server = Koha::OaiServers->find($id);
|
||||
|
||||
unless ($server) {
|
||||
print "OAI Server $id unknown\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
my $script_handler = Koha::Script->new( { script => $0 } );
|
||||
|
||||
try {
|
||||
$script_handler->lock_exec;
|
||||
} catch {
|
||||
my $message = "Skipping execution of $0";
|
||||
print "$message\n" if $verbose;
|
||||
cronlogaction( { info => $message } );
|
||||
exit;
|
||||
};
|
||||
|
||||
cronlogaction( { action => 'Start', info => "Starting OAI Harvest" } );
|
||||
cronlogaction( { info => "Command line: $command_line_options" } );
|
||||
|
||||
my $harvester =
|
||||
Koha::OAI::Client::Harvester->new( { server => $server, verbose => $verbose, days => $days, force => $force } );
|
||||
$harvester->init();
|
||||
|
||||
cronlogaction( { action => 'End', info => "Ending OAI Harvest" } );
|
||||
exit(0);
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Copyright 2024 BibLibre
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
use Test::More tests => 5;
|
||||
use Test::Exception;
|
||||
|
||||
use t::lib::TestBuilder;
|
||||
use HTTP::OAI;
|
||||
use HTTP::OAI::Metadata::OAI_DC;
|
||||
use HTTP::OAI::Record;
|
||||
use HTTP::OAI::Encapsulation;
|
||||
use Koha::Database;
|
||||
use Koha::OaiServer;
|
||||
use Koha::OaiServers;
|
||||
use Koha::OAI::Client::Harvester;
|
||||
|
||||
my $schema = Koha::Database->new->schema;
|
||||
my $builder = t::lib::TestBuilder->new;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my $new_oai_1 = Koha::OaiServer->new(
|
||||
{
|
||||
endpoint => 'my_host1.org',
|
||||
oai_set => 'set1',
|
||||
servername => 'my_test_1',
|
||||
dataformat => 'oai_dc',
|
||||
recordtype => 'biblio',
|
||||
add_xslt => '',
|
||||
}
|
||||
)->store;
|
||||
|
||||
my $harvester = Koha::OAI::Client::Harvester->new( { server => $new_oai_1, verbose => 1, days => 1, force => 1 } );
|
||||
|
||||
my $record =
|
||||
'<metadata xmlns="http://www.openarchives.org/OAI/2.0/"><oai_dc:dc xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd"><dc:title>Pièces diverses </dc:title><dc:identifier>ARCH/0320 [cote]</dc:identifier><dc:relation>FR-920509801 [RCR établissement]</dc:relation><dc:relation>Central obrera boliviana [Fonds ou collection]</dc:relation><dc:format>1 carton</dc:format><dc:date>1971/2000</dc:date><dc:type>Archives et manuscrits</dc:type></oai_dc:dc></metadata>';
|
||||
|
||||
my $r = HTTP::OAI::Record->new();
|
||||
$r->header->datestamp('2017-05-10T09:18:13Z');
|
||||
$r->metadata( HTTP::OAI::Metadata->new( dom => $record ) );
|
||||
|
||||
my $status = $harvester->processRecord($r);
|
||||
is( $status, 'skipped', 'Record with no identifier is skipped' );
|
||||
|
||||
$r->header->identifier('oai:myarchive.org:oid-233');
|
||||
|
||||
$status = $harvester->processRecord($r);
|
||||
is( $status, 'added', 'Record is added' );
|
||||
|
||||
$status = $harvester->processRecord($r);
|
||||
is( $status, 'updated', 'When force is used, record is updated' );
|
||||
|
||||
$harvester = Koha::OAI::Client::Harvester->new( { server => $new_oai_1, verbose => 1, days => 1, force => 0 } );
|
||||
$status = $harvester->processRecord($r);
|
||||
is( $status, 'skipped', 'When force is not used, record is skipped (already up to date)' );
|
||||
|
||||
$r->header->datestamp('2018-05-10T09:18:13Z');
|
||||
$status = $harvester->processRecord($r);
|
||||
is( $status, 'updated', 'When force is not used, record is updated if newer' );
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Copyright 2015 Koha Development team
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
use Test::More tests => 2;
|
||||
use Test::Exception;
|
||||
|
||||
use t::lib::TestBuilder;
|
||||
use Koha::Database;
|
||||
use Koha::OaiServer;
|
||||
use Koha::OaiServers;
|
||||
|
||||
my $schema = Koha::Database->new->schema;
|
||||
my $builder = t::lib::TestBuilder->new;
|
||||
|
||||
subtest 'new, find and delete tests' => sub {
|
||||
plan tests => 4;
|
||||
$schema->storage->txn_begin;
|
||||
my $nb_of_oais = Koha::OaiServers->search->count;
|
||||
my $new_oai_1 = Koha::OaiServer->new(
|
||||
{
|
||||
endpoint => 'my_host1.org',
|
||||
oai_set => 'set1',
|
||||
servername => 'my_test_1',
|
||||
dataformat => 'oai_dc',
|
||||
recordtype => 'biblio',
|
||||
}
|
||||
)->store;
|
||||
my $new_oai_2 = Koha::OaiServer->new(
|
||||
{
|
||||
endpoint => 'my_host2.org',
|
||||
oai_set => 'set2',
|
||||
servername => 'my_test_2',
|
||||
dataformat => 'marcxml',
|
||||
recordtype => 'authority',
|
||||
}
|
||||
)->store;
|
||||
|
||||
like( $new_oai_1->id, qr|^\d+$|, 'Adding a new oai server should have set the id' );
|
||||
is( Koha::OaiServers->search->count, $nb_of_oais + 2, 'The 2 oai servers should have been added' );
|
||||
|
||||
my $retrieved_oai_1 = Koha::OaiServers->find( $new_oai_1->id );
|
||||
is(
|
||||
$retrieved_oai_1->servername, $new_oai_1->servername,
|
||||
'Find a oai server by id should return the correct oai server'
|
||||
);
|
||||
|
||||
$retrieved_oai_1->delete;
|
||||
is( Koha::OaiServers->search->count, $nb_of_oais + 1, 'Delete should have deleted the oai server' );
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
subtest 'Check NOT NULL without default values' => sub {
|
||||
plan tests => 5;
|
||||
$schema->storage->txn_begin;
|
||||
local $SIG{__WARN__} = sub { }; # TODO Needed it for suppressing DBIx warns
|
||||
|
||||
my $server = Koha::OaiServer->new(
|
||||
{
|
||||
oai_set => 'set3',
|
||||
dataformat => 'marcxml',
|
||||
recordtype => 'biblio',
|
||||
}
|
||||
);
|
||||
|
||||
throws_ok { $server->store } 'DBIx::Class::Exception', 'Exception on empty endpoint';
|
||||
like( $@->{msg}, qr/'endpoint' doesn't have a default value/, 'Verified that DBIx blamed endpoint' );
|
||||
|
||||
$server->endpoint('endpoint_added');
|
||||
throws_ok { $server->store } 'DBIx::Class::Exception', 'Exception on empty servername';
|
||||
like( $@->{msg}, qr/'servername' doesn't have a default value/, 'Verified that DBIx blamed servername' );
|
||||
|
||||
$server->servername('servername_added');
|
||||
|
||||
lives_ok { $server->store } 'No exceptions anymore';
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
Loading…
Reference in New Issue