@@ -, +, @@
---------------
---
C4/Installer/PerlDependencies.pm | 5 +
C4/Record.pm | 127 ++-
Koha/Crosswalk/DublinCore.pm | 1011 ++++++++++++++++++++
catalogue/export.pl | 36 +-
debian/control | 6 +-
.../intranet-tmpl/prog/en/css/staff-global.css | 10 +
.../intranet-tmpl/prog/en/includes/cat-toolbar.inc | 2 +-
.../prog/en/modules/catalogue/detail.tt | 159 ++-
koha-tmpl/opac-tmpl/bootstrap/css/opac.css | 2 +-
.../bootstrap/en/includes/opac-detail-sidebar.inc | 5 +-
.../opac-tmpl/bootstrap/en/modules/opac-detail.tt | 162 ++++
koha-tmpl/opac-tmpl/bootstrap/js/script.js | 2 +-
opac/opac-export.pl | 36 +-
t/db_dependent/Record.t | 39 +-
14 files changed, 1544 insertions(+), 58 deletions(-)
create mode 100644 Koha/Crosswalk/DublinCore.pm
--- a/C4/Installer/PerlDependencies.pm
+++ a/C4/Installer/PerlDependencies.pm
@@ -762,6 +762,11 @@ our $PERL_DEPS = {
'required' => '0',
'min_ver' => '0.614',
},
+ 'RDF::Trine' => {
+ 'usage' => 'Core',
+ 'required' => '1',
+ 'min_ver' => '1.000',
+ },
};
1;
--- a/C4/Record.pm
+++ a/C4/Record.pm
@@ -25,7 +25,7 @@ use strict;
# please specify in which methods a given module is used
use MARC::Record; # marc2marcxml, marcxml2marc, changeEncoding
use MARC::File::XML; # marc2marcxml, marcxml2marc, changeEncoding
-use MARC::Crosswalk::DublinCore; # marc2dcxml
+use Koha::Crosswalk::DublinCore; # marc2dcxml
use Biblio::EndnoteStyle;
use Unicode::Normalize; # _entity_encode
use C4::Biblio; #marc2bibtex
@@ -220,20 +220,34 @@ sub marcxml2marc {
=head2 marc2dcxml - Convert from ISO-2709 to Dublin Core
- my ($error,$dcxml) = marc2dcxml($marc,$qualified);
+ ($error,$marc) = marc2dcxml($marc, $type, $qualified,
+ $entities, $root, $xsi_schemaLocation, $rdf_subject, $rdf_format);
Returns a DublinCore::Record object, will eventually return a Dublin Core scalar
-FIXME: should return actual XML, not just an object
+should return actual XML, not just an object (Koha::Crosswalk::DublinCore return an XML)
C<$marc> - an ISO-2709 scalar or MARC::Record object
-C<$qualified> - specify whether qualified Dublin Core should be used in the input or output [0]
+C<$type> - the recommendation ( simple-dc-rdf, dc-rdf, dc-xml, oai-dc, srw_dc )
+
+C<$qualified> - specify whether simple or qualified Dublin Core should be used in output [0 or 1]
+
+C<$entities> placing entities to 0 will codify only the five basic entities e.g., <, >, ", &, and &apos. Conversely if it is encoded to 1, all entities will coded into decimal
+
+C<$root> root element for XML files
+
+C<$xsi_schemaLocation> the xsischemaLocation for XML files.
+
+C<$rdf_subject> Represent the main subject of RDF triples (for Koha the URI of the resource)
+
+C<$rdf_format> Imply multiple formats for RDF (ntriples, nquads, rdfxml, rdfjson, ntriples-canonical, turtle)
=cut
sub marc2dcxml {
- my ($marc,$qualified) = @_;
+ my ( $marc, $type, $qualified, $entities, $root, $xsi_schemaLocation, $rdf_subject,
+ $rdf_format ) = @_;
my $error;
# test if it's already a MARC::Record object, if not, make it one
my $marc_record_obj;
@@ -247,24 +261,93 @@ sub marc2dcxml {
$error .="\nCreation of MARC::Record object failed: ".$MARC::File::ERROR;
}
}
- my $crosswalk = MARC::Crosswalk::DublinCore->new;
- if ($qualified) {
- $crosswalk = MARC::Crosswalk::DublinCore->new( qualified => 1 );
- }
- my $dcxml = $crosswalk->as_dublincore($marc_record_obj);
- my $dcxmlfinal = "\n";
- $dcxmlfinal .= "";
-
- foreach my $element ( $dcxml->elements() ) {
- $dcxmlfinal.="<"."dc:".$element->name().">".$element->content().""."dc:".$element->name().">\n";
+ my $dcxml;
+
+ SWITCH:
+ for ($type) {
+ if (/^simple-dc-rdf/) {
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'rdf',
+ qualified => 0,
+ get_marc_record => $marc,
+ });
+
+ $objectDC->get_rdf_data({
+ rdf_subject => $rdf_subject,
+ rdf_format => $rdf_format,
+ entities => 1,
+ });
+ $dcxml = $objectDC->write_rdf();
+ last SWITCH;
+ }
+ if (/^dc-rdf/) {
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'rdf',
+ qualified => 1,
+ get_marc_record => $marc,
+ });
+
+ $objectDC->get_rdf_data({
+ rdf_subject => $rdf_subject,
+ rdf_format => $rdf_format,
+ entities => 1,
+ });
+ $dcxml = $objectDC->write_rdf();
+ last SWITCH;
+ }
+ if (/^dc-xml/) {
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'xml',
+ qualified => $qualified,
+ get_marc_record => $marc,
+ });
+
+ $objectDC->get_xml_data({
+ root => $root,
+ xsi_schemaLocation => $xsi_schemaLocation,
+ entities => 1,
+ });
+ $dcxml = $objectDC->write_xml();
+ last SWITCH;
+ }
+ if (/^oai-dc/) {
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'xml',
+ qualified => 0,
+ get_marc_record => $marc,
+ });
+
+ $objectDC->get_xml_data({
+ root => 'oai_dc:dc',
+ xsi_schemaLocation => 'http://www.openarchives.org/OAI/2.0/oai_dc/' .
+ ' http://www.openarchives.org/OAI/2.0/oai_dc.xsd',
+ entities => 0,
+ opt_namespace => 'oai_dc',
+ opt_namespace_url => 'http://www.openarchives.org/OAI/2.0/oai_dc/',
+ });
+ $dcxml = $objectDC->write_xml();
+ last SWITCH;
+ }
+ if (/^srw_dc/) {
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'xml',
+ qualified => 0,
+ get_marc_record => $marc,
+ });
+
+ $objectDC->get_xml_data({
+ root => 'srw_dc:dc',
+ xsi_schemaLocation => 'info:srw/schema/1/dc-schema' .
+ ' http://www.loc.gov/standards/sru/resources/dc-schema.xsd',
+ entities => 0,
+ opt_namespace => 'srw_dc',
+ opt_namespace_url => 'info:srw/schema/1/dc-schema',
+ });
+ $dcxml = $objectDC->write_xml();
+ last SWITCH;
+ }
}
- $dcxmlfinal .= "\n";
- return ($error,$dcxmlfinal);
+ return ( $error, $dcxml );
}
=head2 marc2modsxml - Convert from ISO-2709 to MODS
--- a/Koha/Crosswalk/DublinCore.pm
+++ a/Koha/Crosswalk/DublinCore.pm
@@ -0,0 +1,1011 @@
+#!/usr/bin/perl
+package Koha::Crosswalk::DublinCore;
+
+#
+# This file is part of Koha.
+#
+# Copyright (C) 2014 Universidad de El Salvador,
+# Facultad Multidisciplinaria Oriental
+#
+# 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 .
+#
+
+=head1 NAME
+
+Koha::Crosswalk::DublinCore - transform the values of MARC::Crosswalk::DublinCore
+into metadata in XML or RDF format.
+
+=head1 SYNOPSIS
+
+=head2 XML-DC
+
+ use Koha::Crosswalk::DublinCore;
+ use MARC::File::USMARC;
+ my $batch = MARC::File::USMARC->in('in.mrc');
+
+ #the $record will be a MARC::Record object.
+ my $record = $batch->next();
+
+ #Simple DC-XML
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'xml',
+ qualified => 0,
+ get_marc_record => $record});
+
+ #Qualified DC-XML
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'xml',
+ qualified => 1,
+ get_marc_record => $record});
+
+ #After call constructor you need to pass the root element and
+ #the schema in .xsd format. If you prefer or you don't know nothing
+ #about it pass the method in blank, i.e., without arguments.
+ #Also you can determine if you want to encode with xml entities or
+ #just with the five basics entities.
+ #Set entities to 0 for the five basics or 1 to encode with the
+ #complete xml entities.
+ $objectDC->get_xml_data({
+ root => 'metadata',
+ xsi_schemaLocation => 'http://example.org/myapp/' .
+ ' http://example.org/myapp/schema.xsd',
+ });
+ #This print your xml file in STDOUT
+ my $XML-DC = $objectDC->write_xml();
+ print $XML-DC;
+
+ #Close the file according to MARC::File::USMARC
+ $batch->close();
+ undef $batch;
+
+ #Or if you want to generate a file
+ open (OUTPUT, '> dc2xml.xml') or die $!;
+ print OUTPUT $XML-DC;
+ close(OUTPUT);
+
+=head2 DC-RDF
+
+ use Koha::Crosswalk::DublinCore;
+ use MARC::File::USMARC;
+ my $marc = MARC::File::USMARC->in('in.mrc');
+ my $record = $marc->next();
+
+ #Simple DC-RDF is not used but not deprecated, DublinCore
+ #can generate it as follow:
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'rdf',
+ qualified => 0,
+ get_marc_record => $record});
+
+ #DC-RDF
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'rdf',
+ qualified => 1,
+ get_marc_record => $record});
+
+ #The get_rdf_data method for RDF does not need to use the root element
+ #and the schema, but you need to declare the resource being described,
+ #i.e., the record.
+ #Note: For Koha is the IRI identifier of the record
+ $objectDC->get_rdf_data({
+ rdf_subject => 'http://opac.mydomain.edu/cgi-bin/koha/opac-detail.pl?biblionumber=17589',
+ });
+
+ my $XML-RDF = $objectDC->write_rdf();
+ print $XML-RDF;
+ #Close the file according to MARC::File::USMARC
+ $batch->close();
+ undef $marc;
+
+=head1 DESCRIPTION
+
+The Koha::Crosswalk::DublinCore defines the interface to transform
+and manipulate MARC records into DC-XML or DC-RDF recommendation.
+This package transform MARC records to XML or RDF/XML Dublin Core
+and follows the recommendations listed below:
+
+L
+
+L
+This recommendation is superseded by DC-RDFrecommendation but not obsoleted at all.
+
+L
+
+=cut
+
+use Modern::Perl;
+use Carp;
+use utf8;
+use version;
+
+BEGIN {
+ require Exporter;
+
+ # set the version for version checking
+ our $VERSION = version->declare("v0.01");
+
+ # Inherit from Exporter to export functions and variables
+ our @ISA = qw(Exporter);
+
+ # Functions and variables which are exported by default
+ our @EXPORT = qw(new get_xml_data get_rdf_data write_xml write_rdf);
+
+ # Functions and variables which can be optionally exported
+ our @EXPORT_OK =
+ qw(type qualified get_marc_record root xsi_schemaLocation rdf_subject rdf_format opt_namespace opt_namespace_url);
+
+}
+
+use MARC::File::USMARC;
+use MARC::Crosswalk::DublinCore;
+use XML::LibXML;
+use C4::Record;
+use RDF::Trine;
+use base qw(Class::Accessor);
+__PACKAGE__->mk_accessors(
+ qw(type qualified get_marc_record root xsi_schemaLocation rdf_subject rdf_format entities opt_namespace opt_namespace_url)
+);
+
+# Defining some constants
+my $xsi_schema = qq(http://www.w3.org/2001/XMLSchema-instance);
+my $unqualified = qq(http://purl.org/dc/elements/1.1/);
+my $qualified = qq(http://purl.org/dc/terms/);
+my $dcam = qq(http://purl.org/dc/dcam/);
+my $rdfNS = qq(http://www.w3.org/1999/02/22-rdf-syntax-ns#);
+my @elementupcase =
+ qw/tableOfContents dateAccepted dateCopyrighted dateSubmitted isVersionOf hasVersion isReplacedBy isRequiredBy isPartOf hasPart isReferencedBy isFormatOf hasFormat conformsTo accrualMethod accrualPeriodicity accrualPolicy instructionalMethod rightsHolder educationLevel accessRights bibliographicCitation/;
+my $map;
+
+=head2 METHODS
+
+=over 12
+
+=item C
+
+Return a new Koha::Crosswalk::DublinCore object.
+This constructor sets the output type (RDF or XML), the level of the standard (Simple DC or Qualified DC) and the MARC record to be transformed to DC.
+
+ my $objectDC = Koha::Crosswalk::DublinCore->new({
+ type => 'rdf',
+ qualified => 0,
+ get_marc_record => $record});
+
+=cut
+
+sub new {
+ my ( $class, $args ) = @_;
+ $args = {} unless defined $args;
+ return bless( $args, $class );
+}
+
+=item C
+
+This method is just for DC-XML: Fetch the xml root element and the schema in .xsd format.
+
+ $objectDC->get_xml_data({
+ root => 'metadata',
+ xsi_schemaLocation => 'http://example.org/myapp/ http://example.org/myapp/schema.xsd',
+ entities => 1,
+ opt_namespace => 'oai_dc',
+ opt_namespace_url => 'http://www.openarchives.org/OAI/2.0/oai_dc/',
+ });
+
+The entities argument is for extended xml entities, i.e., placing entities to zero will codify only the five basic entities e.g., <, >, ", &, and &apos. Conversely if it is encoded to one, all entities will coded into decimal.
+
+Additionally, has been included the opt_namespace and opt_namespace_url arguments to include another XML name space, like OAI-DC or SRW-DC.
+
+NOTE: This method is only for use of the DC-XML recommendation, i.e., type => 'xml'.
+See C method or the section SYNOPSIS.
+
+=cut
+
+sub get_xml_data {
+
+ my $self = shift;
+ my ($args) = @_;
+
+ if (@_) {
+ $self->root( $args->{root} );
+ $self->xsi_schemaLocation( $args->{xsi_schemaLocation} );
+ $self->entities( $args->{entities} );
+ $self->opt_namespace( $args->{opt_namespace} );
+ $self->opt_namespace_url( $args->{opt_namespace_url} );
+ }
+
+ #if data not filled
+ $self->{root} = "metadata" unless ( defined $self->{root} );
+ $self->{entities} = 0 unless ( defined $self->{entities} );
+ my %dataxml = (
+ xmlroot => $self->{root},
+ entities => $self->{entities},
+ opt_namespace => $self->{opt_namespace},
+ opt_namespace_url => $self->{opt_namespace_url},
+ );
+
+ if ( exists $self->{xsi_schemaLocation} ) {
+ $dataxml{'xsi_schemaLocation'} = $self->{xsi_schemaLocation};
+ }
+ if ( exists $self->{xsi_schemaLocation} ) {
+ $dataxml{'opt_namespace'} = $self->{opt_namespace};
+ }
+ if ( exists $self->{xsi_schemaLocation} ) {
+ $dataxml{'opt_namespace_url'} = $self->{opt_namespace_url};
+ }
+ return \%dataxml;
+}
+
+=item C
+
+This method is only for DC-RDF: Fetch the IRI identifier of the resource being described. As well, you can pass the format you want to generate with the rdf, by default the DC-RDF specify RDF/XML but RDF can represent in other formats listed below:
+
+. ntriples
+
+. nquads
+
+. rdfxml
+
+. rdfjson
+
+. ntriples-canonical
+
+. turtle
+
+ $objectDC->get_rdf_data({
+ rdf_subject => 'http://opac.mydomain.edu/cgi-bin/koha/opac-detail.pl?biblionumber=17589',
+ rdf_format => 'rdfxml',
+ entities => 0|1,
+ });
+
+NOTE: The entities is needed only for rdfxml value and is used like C method.
+
+=cut
+
+sub get_rdf_data {
+
+ my $self = shift;
+ my ($args) = @_;
+
+ if (@_) {
+ $self->rdf_subject( $args->{rdf_subject} );
+ $self->rdf_format( $args->{rdf_format} );
+ $self->entities( $args->{entities} );
+ }
+
+ #if data not filled
+ $self->{rdf_subject} = "http://koha-community.org/"
+ unless ( defined $self->{rdf_subject} );
+ $self->{rdf_format} = "rdfxml" unless ( defined $self->{rdf_format} );
+ $self->{entities} = 0 unless ( defined $self->{entities} );
+ my %rdfdescription = (
+ rdf_subject => $self->{rdf_subject},
+ rdf_format => $self->{rdf_format},
+ entities => $self->{entities},
+ );
+
+ return \%rdfdescription;
+}
+
+=item C
+
+Get the MARC record and return a Dublin Core elements, passed as argument in dc_order_execution method.
+
+USAGE:
+ my dc = $self->conversion_to_dc();
+ $self->dc_order_execution ($dc, $dcxml, $root);
+
+=cut
+
+sub conversion_to_dc {
+
+ my $self = shift;
+ my $marc_record_obj = $self->get_marc_record();
+ my $crosswalk;
+ my $dc;
+
+ #if data not filled
+ $self->qualified(0) unless ( exists $self->{qualified} );
+ if ( $self->qualified() != 0 and $self->qualified() != 1 )
+ {
+ croak "Only the 0 or 1 values are accepted\n" .
+ "Set qualified => " . $self->qualified() . " is no good, stopped";
+ }
+ if ( $self->qualified() == 1 ) {
+ $crosswalk = MARC::Crosswalk::DublinCore->new( qualified => 1 );
+ }
+ elsif ( $self->qualified() == 0 ) {
+ $crosswalk = MARC::Crosswalk::DublinCore->new( qualified => 0 );
+ }
+ if ( $marc_record_obj =~ /^MARC::Record/ ) {
+ $dc = $crosswalk->as_dublincore($marc_record_obj);
+ }
+ else {
+ croak "MARC::Record object failed or not a MARC::Record\n" .
+ "Stopped due get_marc_record => is not a MARC::Record";
+ }
+
+ return $dc;
+
+}
+=item C
+
+Return the xml object as string.
+
+NOTE: This method is only for use of the DC-XML recommendation, i.e., type => 'xml'.
+See C and C methods or the section SYNOPSIS.
+
+=cut
+
+sub write_xml {
+ my $self = shift;
+ my $dataxml = $self->get_xml_data();
+ my $dc = $self->conversion_to_dc();
+
+ #Looking for bad data
+ if ( $self->type() ne 'xml' and $self->type() ne 'rdf' )
+ {
+ croak "Only the xml or rdf values are accepted\n" .
+ "Set type => " . $self->type() . " is no good, stopped";
+ }
+ elsif ( $self->type() eq 'rdf' )
+ {
+ croak "The constructor specified rdf\n" .
+ "Cannot use this method with rdf. This is no good, stopped";
+ }
+
+ if ( $self->entities() != 0 and $self->entities() != 1 )
+ {
+ croak "Only the 0 or 1 values are accepted\n" .
+ "Set entities => " . $self->entities() . " is no good, stopped";
+ }
+
+ #Creating XML object
+ my $doc = XML::LibXML::Document->new( '1.0', 'utf-8' );
+ my $root = $doc->createElement( $dataxml->{'xmlroot'} );
+ $root->setNamespace( $xsi_schema, 'xsi', 0 );
+
+ if ( defined $dataxml->{'opt_namespace'} ) {
+ $root->setNamespace( $dataxml->{'opt_namespace_url'},
+ $dataxml->{'opt_namespace'}, 0 );
+ }
+
+ if ( $self->type() eq 'xml' ) {
+ if ( $self->qualified() == 0 ) {
+ if ( defined $dataxml->{'xsi_schemaLocation'} ) {
+ $root->setAttribute(
+ 'xsi:schemaLocation' => $dataxml->{'xsi_schemaLocation'} );
+ $root->setNamespace( $unqualified, 'dc', 0 );
+ $self->dc_order_execution( $dc, $doc, $root );
+ }
+ else {
+ $root->setNamespace( $unqualified, 'dc', 0 );
+ $self->dc_order_execution( $dc, $doc, $root );
+ }
+ }
+ elsif ( $self->qualified() == 1 ) {
+ if ( defined $dataxml->{'xsi_schemaLocation'} ) {
+ $root->setAttribute(
+ 'xsi:schemaLocation' => $dataxml->{'xsi_schemaLocation'} );
+ $root->setNamespace( $unqualified, 'dc', 0 );
+ $root->setNamespace( $qualified, 'dcterms', 0 );
+ $self->dc_order_execution( $dc, $doc, $root );
+ }
+ else {
+ $root->setNamespace( $unqualified, 'dc', 0 );
+ $root->setNamespace( $qualified, 'dcterms', 0 );
+ $self->dc_order_execution( $dc, $doc, $root );
+ }
+ }
+ }
+
+ $doc->setDocumentElement($root);
+
+ #Enabling or desabling entities and print the xml and, decoding string to utf8
+ if ( $dataxml->{'entities'} == 1 ) {
+ my $serialized_data = $doc->toString(1);
+ utf8::decode($serialized_data);
+ my ($dcxml_entity_encoded) = C4::Record::_entity_encode($serialized_data);
+ $serialized_data = $dcxml_entity_encoded;
+ return $serialized_data;
+ }
+ else {
+ return $doc->toString(1);
+ }
+}
+
+=item C
+
+Return the rdf object as string.
+
+NOTE: This method is only for use of the DC-RDF recommendation, i.e., type => 'rdf'.
+See C and C methods or the section SYNOPSIS.
+
+=cut
+
+sub write_rdf {
+ my $self = shift;
+ my $rdfdescription = $self->get_rdf_data();
+ my $dc = $self->conversion_to_dc();
+ my $serializer;
+ my %namespaces;
+
+ #Looking for bad data
+ if ( $self->type() ne 'xml' and $self->type() ne 'rdf' )
+ {
+ croak "Only the xml or rdf values are accepted\n" .
+ "Set type => " . $self->type() . " is no good, stopped";
+ }
+ elsif ( $self->type() eq 'xml' ) {
+ croak "The constructor specified xml\n" .
+ "Cannot use this method with xml. This is no good, stopped";
+ }
+
+ if ( $self->entities() != 0 and $self->entities() != 1 )
+ {
+ croak "Only the 0 or 1 values are accepted\n" .
+ "Set entities => " . $self->entities() . " is no good, stopped";
+ }
+
+ # Creating the triple store in temporary data
+ my $store = RDF::Trine::Store::Memory->new();
+
+ # Creating the model
+ my $rdf = RDF::Trine::Model->new($store);
+
+ # Creating the subject
+ my $subject =
+ RDF::Trine::Node::Resource->new( $rdfdescription->{'rdf_subject'} );
+
+ $namespaces{'rdf'} = $rdfNS;
+
+ if ( $self->qualified() == 0 ) {
+
+ # Declaring all namespaces in a hash
+ $namespaces{'dc'} = $unqualified;
+ }
+ else {
+
+ # Declaring all namespaces in a hash
+ $namespaces{'dcterms'} = $qualified;
+ $namespaces{'dcam'} = $dcam;
+ }
+
+ # Creating namespaces
+ $map = RDF::Trine::NamespaceMap->new( \%namespaces );
+
+ if ( $self->type() eq 'rdf' ) {
+ $self->dc_order_execution( $dc, $rdf, $subject );
+ }
+
+ #Enabling or desabling entities and print the xml and, decoding string to utf8
+ if ( $rdfdescription->{'rdf_format'} eq 'rdfxml' ) {
+ if ( $rdfdescription->{'entities'} == 1 ) {
+ $serializer =
+ RDF::Trine::Serializer::RDFXML->new(
+ namespaces => {%namespaces} );
+ my $serialized_data = $serializer->serialize_model_to_string($rdf);
+ utf8::decode($serialized_data);
+ my ($dcxml_entity_encoded) = C4::Record::_entity_encode($serialized_data);
+ return $serialized_data = $dcxml_entity_encoded;
+ }
+ else {
+ $serializer =
+ RDF::Trine::Serializer::RDFXML->new(
+ namespaces => {%namespaces} );
+ return $serializer->serialize_model_to_string($rdf);
+ }
+ }
+ elsif ( $rdfdescription->{'rdf_format'} eq 'turtle' ) {
+ $serializer =
+ RDF::Trine::Serializer::Turtle->new( namespaces => {%namespaces} );
+ return $serializer->serialize_model_to_string($rdf);
+ }
+ else {
+ $serializer =
+ RDF::Trine::Serializer->new( $rdfdescription->{'rdf_format'} );
+ return $serializer->serialize_model_to_string($rdf);
+ }
+}
+
+=item C
+
+This subroutine define if is necessary to convert lowercase some qualifiers or let them as crosswalk method basis
+
+USAGE: upper_or_lowercase (element->qualifier())
+
+=cut
+
+sub upper_or_lowercase {
+
+
+ my $dcelement = $_[0];
+ my $count = 0;
+ my $result;
+ while ( $count <= $#elementupcase ) {
+ if ( $elementupcase[$count] eq $dcelement ) {
+ $result = $dcelement;
+ last;
+ }
+ elsif ( $dcelement ne $elementupcase[$count] ) {
+ $result = lc($dcelement);
+ $count++;
+ next;
+ }
+ }
+
+ return $result;
+
+}
+
+=item C
+
+xml_constructor ( doc, root, namespace, attr, element_name, element_content, element_qualifier, element_scheme )
+
+USAGE: define all posible elements (name, content, qualifier, scheme) as neccesary
+doc: the XML object
+root: append root to doc
+namespace: defined as "dc" or "dcterms"
+attr: a boolean value to determinate xsi:type xml namespace for dcterms
+Examples:
+xml_constructor ( $dcxml, $root, "dc", 0, element->name(), element->content() );
+xml_constructor ( $dcxml, $root, "dcterms", 1, element->name(), element->content(), $element->qualifier() );
+
+NOTE: This is a routine not a method.
+
+=cut
+
+sub xml_constructor {
+
+ my ( $doc, $root, $namespace, $attr, $element_name, $element_content,
+ $element_qualifier, $element_scheme )
+ = @_;
+
+ # This scalar is used for deleting spaces in scheme elements
+ my $deletespaces;
+
+ # This scalar is used for making upper or lowercase the qualifier elements
+ my $lowercase;
+ my $tagxml;
+
+ if ( $namespace eq "dc" ) {
+ $lowercase = lc($element_name);
+ }
+ elsif ( $namespace eq "dcterms" ) {
+ $lowercase = upper_or_lowercase($element_qualifier);
+
+ #replacing spacial to spatial, bug from dublin or crosswalk.
+ $lowercase =~ s/spacial/spatial/;
+ }
+
+ if ( ( $namespace eq "dc" or "dcterms" ) and $attr == 0 ) {
+
+ # This will do something like: Title
+ $tagxml = XML::LibXML::Element->new($lowercase);
+ $tagxml->setNamespace( undef, $namespace, 1 );
+ $tagxml->appendTextNode($element_content);
+ $root->appendChild($tagxml);
+ }
+ elsif ( ( $namespace eq "dcterms" ) and $attr == 1 ) {
+
+# This will do something like: us
+ $deletespaces = $element_scheme;
+ $deletespaces =~ s/\s//;
+ $tagxml = XML::LibXML::Element->new($lowercase);
+ $tagxml->setNamespace( undef, $namespace, 1 );
+ my $attribute = $namespace . ':' . $deletespaces;
+ $tagxml->setAttribute( 'xsi:type', $attribute );
+ $tagxml->appendTextNode($element_content);
+ $root->appendChild($tagxml);
+ }
+ elsif ( ( $namespace eq "dc" ) and $attr == 1 ) {
+
+# This will do something like: Water supply.
+ if ( $element_scheme ne "DCMI Type Vocabulary" )
+ { #Dublin core returns DCMI Type Vocabulary
+ $deletespaces = $element_scheme;
+ $deletespaces =~ s/\s//;
+ $tagxml = XML::LibXML::Element->new($lowercase);
+ $tagxml->setNamespace( undef, $namespace, 1 );
+ my $attribute = 'dcterms:' . $deletespaces;
+ $tagxml->setAttribute( 'xsi:type', $attribute );
+ $tagxml->appendTextNode($element_content);
+ $root->appendChild($tagxml);
+ }
+ elsif ( $element_scheme eq "DCMI Type Vocabulary" )
+ { #Changing for DCMIType
+ # This will do something like: Text
+ $tagxml = XML::LibXML::Element->new($lowercase);
+ $tagxml->setNamespace( undef, $namespace, 1 );
+ $tagxml->setAttribute( 'xsi:type', 'dcterms:DCMIType' );
+ $tagxml->appendTextNode($element_content);
+ $root->appendChild($tagxml);
+ }
+ } #if...elsif
+
+ return $tagxml;
+
+} #subroutine
+
+=item C
+
+xml_constructor ( rdf, subject, namespace, attr, element_name, element_content, element_qualifier, element_scheme )
+
+USAGE: define all posible elements (name, content, qualifier, scheme) as neccesary
+rdf: the RDF object
+subject: the subject for the triples
+namespace: defined as "dc" or "dcterms". This is for Simple DC or DC-RDF recommendations.
+attr: a boolean value to determine the nodeID attribute for dcterms
+
+NOTE: This is a routine not a method.
+
+=cut
+
+sub rdf_constructor {
+
+ my ( $rdf, $subject, $namespace, $attr, $element_name, $element_content,
+ $element_qualifier, $element_scheme )
+ = @_;
+
+ #This scalar is used for deleting spaces in scheme elements
+ my $deletespaces;
+
+ #This scalar is used for making upper or lowercase the qualifier elements
+ my $lowercase;
+
+ if ( $namespace eq "dc" ) {
+ $lowercase = lc($element_name);
+ }
+ elsif ( $namespace eq "dcterms" ) {
+ $lowercase = upper_or_lowercase($element_qualifier);
+
+ #replacing spacial to spatial, bug from dublin or crosswalk.
+ $lowercase =~ s/spacial/spatial/;
+ }
+
+ if ( ( $namespace eq "dc" or "dcterms" ) and $attr == 0 ) {
+
+ # This will do something like: Title
+ my $predicate = undef;
+ if ( $namespace eq "dc" ) {
+ $predicate = $map->dc($lowercase);
+ }
+ else {
+ $predicate = $map->dcterms($lowercase);
+ }
+ my $object = RDF::Trine::Node::Literal->new($element_content);
+ my $statement =
+ RDF::Trine::Statement->new( $subject, $predicate, $object );
+ $rdf->add_statement($statement);
+ }
+ elsif ( ( $namespace eq "dc" ) and $attr == 2 ) {
+
+ # This will do something like: Title
+ my $predicate = $map->dcterms($lowercase);
+ my $object = RDF::Trine::Node::Literal->new($element_content);
+ my $statement =
+ RDF::Trine::Statement->new( $subject, $predicate, $object );
+ $rdf->add_statement($statement);
+ }
+ elsif ( ( $namespace eq "dc" ) and $attr == 1 ) {
+ $deletespaces = $element_scheme;
+ $deletespaces =~ s/\s//;
+ SWITCH:
+ for ($element_scheme) {
+ if (/^ISO 3166/) {
+
+ # Dublin core returns DCMI Type Vocabulary
+ # This will do something like:
+ #
+ #
+ # us
+ #
+ #
+ my $objectbnode = RDF::Trine::Node::Blank->new('country');
+ my $predicate = $map->dcterms($lowercase);
+ my $object = RDF::Trine::Node::Literal->new($element_content);
+ my $dcam_member_of = $map->dcam('memberOf');
+ my $resource_schema = $map->dcterms($deletespaces);
+ my $rdf_value = $map->rdf('value');
+ my $statement1 =
+ RDF::Trine::Statement->new( $subject, $predicate,
+ $objectbnode );
+ my $statement2 =
+ RDF::Trine::Statement->new( $objectbnode, $dcam_member_of,
+ $resource_schema );
+ my $statement3 =
+ RDF::Trine::Statement->new( $objectbnode, $rdf_value,
+ $object );
+ $rdf->add_statement($statement1);
+ $rdf->add_statement($statement2);
+ $rdf->add_statement($statement3);
+ last SWITCH;
+ }
+ if (/^DCMI Type Vocabulary/) { #Changing for DCMIType
+ my $objectbnode = RDF::Trine::Node::Blank->new('DCMIType');
+ my $predicate = $map->dcterms($lowercase);
+ my $object = RDF::Trine::Node::Literal->new($element_content);
+ my $dcam_member_of = $map->dcam('memberOf');
+ my $resource_schema = $map->dcterms('DCMIType');
+ my $rdf_value = $map->rdf('value');
+ my $statement1 =
+ RDF::Trine::Statement->new( $subject, $predicate,
+ $objectbnode );
+ my $statement2 =
+ RDF::Trine::Statement->new( $objectbnode, $dcam_member_of,
+ $resource_schema );
+ my $statement3 =
+ RDF::Trine::Statement->new( $objectbnode, $rdf_value,
+ $object );
+ $rdf->add_statement($statement1);
+ $rdf->add_statement($statement2);
+ $rdf->add_statement($statement3);
+ last SWITCH;
+ }
+ if (/^ISO 639-2/) { #Changing bnodeId ISO639-2 for language
+ my $objectbnode = RDF::Trine::Node::Blank->new('language');
+ my $predicate = $map->dcterms($lowercase);
+ my $object = RDF::Trine::Node::Literal->new($element_content);
+ my $dcam_member_of = $map->dcam('memberOf');
+ my $resource_schema = $map->dcterms($deletespaces);
+ my $rdf_value = $map->rdf('value');
+ my $statement1 =
+ RDF::Trine::Statement->new( $subject, $predicate,
+ $objectbnode );
+ my $statement2 =
+ RDF::Trine::Statement->new( $objectbnode, $dcam_member_of,
+ $resource_schema );
+ my $statement3 =
+ RDF::Trine::Statement->new( $objectbnode, $rdf_value,
+ $object );
+ $rdf->add_statement($statement1);
+ $rdf->add_statement($statement2);
+ $rdf->add_statement($statement3);
+ last SWITCH;
+ }
+ if (/^RFC 1766/) { #Changing bnodeId RFC1766 for languagetag
+ my $objectbnode = RDF::Trine::Node::Blank->new('languagetag');
+ my $predicate = $map->dcterms($lowercase);
+ my $object = RDF::Trine::Node::Literal->new($element_content);
+ my $dcam_member_of = $map->dcam('memberOf');
+ my $resource_schema = $map->dcterms($deletespaces);
+ my $rdf_value = $map->rdf('value');
+ my $statement1 =
+ RDF::Trine::Statement->new( $subject, $predicate,
+ $objectbnode );
+ my $statement2 =
+ RDF::Trine::Statement->new( $objectbnode, $dcam_member_of,
+ $resource_schema );
+ my $statement3 =
+ RDF::Trine::Statement->new( $objectbnode, $rdf_value,
+ $object );
+ $rdf->add_statement($statement1);
+ $rdf->add_statement($statement2);
+ $rdf->add_statement($statement3);
+ last SWITCH;
+ }
+ if ( /^LCSH/ || /^MeSH/ || /^LCC/ || /^DDC/ ||
+ /^UDC/ || /^IMT/ || /^URI/ || /^TGN/ )
+ { #Scheme sharing common elements
+ my $objectbnode = RDF::Trine::Node::Blank->new($deletespaces);
+ my $predicate = $map->dcterms($lowercase);
+ my $object = RDF::Trine::Node::Literal->new($element_content);
+ my $dcam_member_of = $map->dcam('memberOf');
+ my $resource_schema = $map->dcterms($deletespaces);
+ my $rdf_value = $map->rdf('value');
+ my $statement1 =
+ RDF::Trine::Statement->new( $subject, $predicate,
+ $objectbnode );
+ my $statement2 =
+ RDF::Trine::Statement->new( $objectbnode, $dcam_member_of,
+ $resource_schema );
+ my $statement3 =
+ RDF::Trine::Statement->new( $objectbnode, $rdf_value,
+ $object );
+ $rdf->add_statement($statement1);
+ $rdf->add_statement($statement2);
+ $rdf->add_statement($statement3);
+ last SWITCH;
+ }
+ }
+ } #if-elsif
+ return $rdf;
+} #subroutine
+
+=item C
+
+USAGE: Get the parameters for xml or rdf and execute in sequence.
+
+ my dc = $self->conversion_to_dc();
+ $self->dc_order_execution ($dc, $dcxml, $root);
+
+=back
+
+=cut
+
+sub dc_order_execution {
+
+ my $self = shift;
+
+ if ( $self->type() eq 'xml' ) { #Order for xml
+ my ( $dc, $dcxml, $root ) = @_;
+ foreach my $element ( $dc->elements() ) {
+ SWITCH: {
+ if ( $element->name()
+ and not defined $element->scheme()
+ and not defined $element->qualifier() )
+ {
+ $dcxml =
+ xml_constructor( $dcxml, $root, "dc", 0, $element->name(),
+ $element->content() );
+ last SWITCH;
+ }
+
+ if ( $element->name()
+ and not defined $element->scheme()
+ and not defined $element->qualifier() )
+ {
+ $dcxml =
+ xml_constructor( $dcxml, $root, "dcterms", 0,
+ $element->name(), $element->content() );
+ last SWITCH;
+ }
+
+ if ( $element->name()
+ and $element->scheme()
+ and $element->qualifier() )
+ {
+ $dcxml = xml_constructor(
+ $dcxml, $root,
+ "dcterms", 1,
+ $element->name(), $element->content(),
+ $element->qualifier(), $element->scheme()
+ );
+ last SWITCH;
+ }
+
+ if ( $element->name()
+ and $element->scheme()
+ and ( $element->scheme ne "DCMI Type Vocabulary" ) )
+ {
+ $dcxml =
+ xml_constructor( $dcxml, $root, "dc", 1, $element->name(),
+ $element->content(), $element->qualifier(),
+ $element->scheme() );
+ last SWITCH;
+ }
+
+ if ( $element->name()
+ and $element->scheme()
+ and ( $element->scheme() eq "DCMI Type Vocabulary" ) )
+ {
+ $dcxml =
+ xml_constructor( $dcxml, $root, "dc", 1, $element->name(),
+ $element->content(), $element->qualifier(),
+ $element->scheme() );
+ last SWITCH;
+ }
+
+ if ( $element->name() and $element->qualifier() ) {
+ $dcxml = xml_constructor(
+ $dcxml, $root,
+ "dcterms", 0,
+ $element->name(), $element->content(),
+ $element->qualifier(), $element->scheme()
+ );
+ last SWITCH;
+ } #if
+ } #SWITCH
+ } #foreach 1
+ }
+ elsif ( $self->type() eq 'rdf' ) { #Order for rdf/xml
+ my ( $dc, $rdf, $subject ) = @_;
+ foreach my $element ( $dc->elements() ) {
+ SWITCH: {
+ if ( $element->name()
+ and not defined $element->scheme()
+ and not defined $element->qualifier() )
+ {
+ rdf_constructor( $rdf, $subject, "dc", 0, $element->name(),
+ $element->content() )
+ unless $self->qualified() == 1;
+ rdf_constructor( $rdf, $subject, "dc", 2, $element->name(),
+ $element->content() )
+ unless $self->qualified() == 0;
+ last SWITCH;
+ }
+
+ if ( $element->name()
+ and $element->scheme()
+ and ( $element->scheme ne "DCMI Type Vocabulary" ) )
+ {
+ rdf_constructor( $rdf, $subject, "dc", 1, $element->name(),
+ $element->content(), $element->qualifier(),
+ $element->scheme() );
+ last SWITCH;
+ }
+
+ if ( $element->name()
+ and $element->scheme()
+ and ( $element->scheme() eq "DCMI Type Vocabulary" ) )
+ {
+ rdf_constructor( $rdf, $subject, "dc", 1, $element->name(),
+ $element->content(), $element->qualifier(),
+ $element->scheme() );
+ last SWITCH;
+ }
+
+ if ( $element->name() and $element->qualifier() ) {
+ rdf_constructor(
+ $rdf, $subject,
+ "dcterms", 0,
+ $element->name(), $element->content(),
+ $element->qualifier(), $element->scheme()
+ );
+ last SWITCH;
+ } #if
+ } #SWITCH
+ } #foreach 2
+ }
+ return;
+}
+
+END {
+
+ #When opened with MARC::File::USMARC, close marc record if not closed
+ sub DESTROY {
+ my $self = shift;
+ if ( $self->{get_marc_record} =~ /^MARC:File::USMARC/ ) {
+ $self->{get_marc_record}->close();
+ undef $self->{get_marc_record};
+ }
+ }
+}
+1;
+__END__
+
+=head1 VERSION
+
+version 0.01
+
+=head1 RELATES MODULES
+
+This package requires the following modules:
+
+L
+
+L
+
+L
+
+L
+
+L
+
+L
+
+L
+
+=head1 SEE ALSO
+
+Dublin Core Web Page L.
+
+=head1 LICENSE
+
+Copyright (c) 2014 Koha Community. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
+
+=head1 AUTHOR
+
+Hector Eduardo Catro Avalos E hector.hecaxmmx at gmail dot com E
+and the Koha Development Team.
+
+=cut
--- a/catalogue/export.pl
+++ a/catalogue/export.pl
@@ -26,6 +26,14 @@ my $format=$query->param("format");
my $error = '';
if ($op eq "export") {
my $biblionumber = $query->param("bib");
+ my $recommendation = $query->param("recommendation");
+ my $formats = $query->param("formats");
+ my $qualifier = $query->param("qualifier");
+ my $root_element = $query->param("root_element");
+ my $xsischemalocation = $query->param("xsischemalocation");
+ my $resource_url = $query->url(-base => 1) .
+ '/cgi-bin/koha/catalogue/detail.pl?biblionumber=' .
+ $biblionumber;
if ($biblionumber){
my $marc = GetMarcBiblio($biblionumber, 1);
@@ -51,8 +59,32 @@ if ($op eq "export") {
$format = "bibtex";
}
elsif ($format =~ /dc/) {
- ($error,$marc) = marc2dcxml($marc,1);
- $format = "dublin-core.xml";
+ SWITCH:
+ for ($recommendation) {
+ if (/^simple-dc-rdf/) {
+ ($error,$marc) = marc2dcxml($marc, $recommendation, 0,
+ 1, undef, undef, $resource_url , $formats);
+ $format = "dublin-core." . $formats;
+ last SWITCH; }
+ if (/^dc-rdf/) {
+ ($error,$marc) = marc2dcxml($marc, $recommendation, 1,
+ 1, undef, undef, $resource_url, $formats);
+ $format = "dublin-core." . $formats;
+ last SWITCH; }
+ if (/^dc-xml/) {
+ ($error,$marc) = marc2dcxml($marc, $recommendation, $qualifier,
+ 1, $root_element, $xsischemalocation, undef, undef);
+ $format = "dublin-core.xml";
+ last SWITCH; }
+ if (/^oai-dc/) {
+ ($error,$marc) = marc2dcxml($marc, $recommendation);
+ $format = "dublin-core.xml";
+ last SWITCH; }
+ if (/^srw_dc/) {
+ ($error,$marc) = marc2dcxml($marc, $recommendation);
+ $format = "dublin-core.xml";
+ last SWITCH; }
+ }
}
elsif ($format =~ /marc8/) {
$marc = changeEncoding($marc,"MARC","MARC21","MARC-8");
--- a/debian/control
+++ a/debian/control
@@ -86,11 +86,11 @@ Build-Depends: libalgorithm-checkdigits-perl,
libopenoffice-oodoc-perl,
libpdf-api2-perl,
libpdf-api2-simple-perl,
- libpdf-fromhtml-perl,
libpdf-reuse-barcode-perl,
libpdf-reuse-perl,
libpdf-table-perl,
libplack-middleware-reverseproxy-perl,
+ librdf-trine-perl,
libscalar-list-utils-perl,
libschedule-at-perl,
libsms-send-perl,
@@ -99,7 +99,6 @@ Build-Depends: libalgorithm-checkdigits-perl,
libtemplate-perl,
libtemplate-plugin-htmltotext-perl,
libtemplate-plugin-json-escape-perl,
- libtemplate-plugin-stash-perl,
libtest-deep-perl,
libtest-harness-perl | perl-modules,
libtest-mockmodule-perl,
@@ -290,11 +289,11 @@ Depends: libalgorithm-checkdigits-perl,
libopenoffice-oodoc-perl,
libpdf-api2-perl,
libpdf-api2-simple-perl,
- libpdf-fromhtml-perl,
libpdf-reuse-barcode-perl,
libpdf-reuse-perl,
libpdf-table-perl,
libplack-middleware-reverseproxy-perl,
+ librdf-trine-perl,
libscalar-list-utils-perl,
libschedule-at-perl,
libsms-send-perl,
@@ -303,7 +302,6 @@ Depends: libalgorithm-checkdigits-perl,
libtemplate-perl,
libtemplate-plugin-htmltotext-perl,
libtemplate-plugin-json-escape-perl,
- libtemplate-plugin-stash-perl,
libtest-deep-perl,
libtest-harness-perl | perl-modules,
libtest-mockmodule-perl,
--- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css
+++ a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css
@@ -2798,3 +2798,13 @@ div#cn_browser_table_wrapper > table#cn_browser_table {
margin: auto;
width:90%;
}
+
+/* CSS for Dublin Core Modal */
+
+#dc-rdf, #dc-xml {
+ display: none;
+}
+
+.label_dc {
+ cursor: pointer;
+}
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc
+++ a/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc
@@ -217,7 +217,7 @@ CAN_user_serials_create_subscription ) %]