Bug 13642 - Adding new features for Dublin Core metadata
authorHector Castro <hector.hecaxmmx@gmail.com>
Mon, 9 Nov 2015 05:22:47 +0000 (23:22 -0600)
committerBrendan A Gallagher <brendan@bywatersolutions.com>
Wed, 27 Jan 2016 06:23:07 +0000 (06:23 +0000)
When Koha export a bibliographic record to DC, makes it in XML format.
This XML not follows the DC-XML recommendations as should be: elements
in uppercase eg. dc:Date, dc:Creator, section 4.2, recommendation 4
explain that "The property names for the 15 DC elements should be all
lower-case." eg. dc:date, dc:creator" and section "4.3 Example - a
simple DC record", xsi:schemaLocation="http://example.org/myapp/
http://example.org/myapp/schema.xsd" schema does not exist.

NOTE: This new feature implement the XSLT transformation for OAI-DC,
SRW-DC and RDF-DC

Test plan
---------------
1) Download Dublin Core file from record detail page. Open up the file,
   and make sure that the document not follows the DC-XML
   recommendations as should be.
2) Apply patch.
3) Go to whichever bib record in OPAC or staff and click on Save >
   Dublin Core.  A modal will display, prove all options.
4) Change the system preference 'Opac ExportOptions' by enabling and
   disabling Dublin Core and try to download a record.
5) Try several bibliographic records in any format (book, magazine, DVD,
   etc.) to confirm that properly exported.
6) Test with all marc flavours.

Sponsored-by: Universidad de El Salvador
Signed-off-by: Frederic Demians <f.demians@tamil.fr>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Brendan A Gallagher <brendan@bywatersolutions.com>
C4/Record.pm
catalogue/export.pl
koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc
koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt
koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt
koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-detail-sidebar.inc
koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt
koha-tmpl/opac-tmpl/bootstrap/less/opac.less
opac/opac-export.pl

index f46651b..1360155 100644 (file)
@@ -2,6 +2,7 @@ package C4::Record;
 #
 # Copyright 2006 (C) LibLime
 # Parts copyright 2010 BibLibre
+# Part copyright 2015 Universidad de El Salvador
 #
 # This file is part of Koha.
 #
@@ -25,7 +26,6 @@ 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 Biblio::EndnoteStyle;
 use Unicode::Normalize; # _entity_encode
 use C4::Biblio; #marc2bibtex
@@ -36,6 +36,8 @@ use YAML; #marcrecords2csv
 use Template;
 use Text::CSV::Encoded; #marc2csv
 use Koha::SimpleMARC qw(read_field);
+use Koha::XSLT_Handler;
+use Carp;
 
 use vars qw($VERSION @ISA @EXPORT);
 
@@ -220,51 +222,92 @@ sub marcxml2marc {
 
 =head2 marc2dcxml - Convert from ISO-2709 to Dublin Core
 
-  my ($error,$dcxml) = marc2dcxml($marc,$qualified);
+    my dcxml = marc2dcxml ($marc, $xml, $biblionumber, $format);
 
-Returns a DublinCore::Record object, will eventually return a Dublin Core scalar
+EXAMPLE
 
-FIXME: should return actual XML, not just an object
+    my dcxml = marc2dcxml (undef, undef, 1, "oaidc");
+
+Convert MARC or MARCXML to Dublin Core metadata (XSLT Transformation),
+optionally can get an XML directly from database (biblioitems.marcxml)
+without item information. This method take into consideration the syspref
+'marcflavour' (UNIMARC, MARC21 and NORMARC).
+Return an XML file with the format defined in C<$format>
 
 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<$xml> - a MARCXML file
+
+C<$biblionumber> - obtain the record directly from database (biblioitems.marcxml)
+
+C<$format> - accept three type of DC formats (oaidc, srwdc, and rdfdc )
 
 =cut
 
 sub marc2dcxml {
-       my ($marc,$qualified) = @_;
-       my $error;
-    # test if it's already a MARC::Record object, if not, make it one
-    my $marc_record_obj;
-    if ($marc =~ /^MARC::Record/) { # it's already a MARC::Record object
-        $marc_record_obj = $marc;
-    } else { # it's not a MARC::Record object, make it one
-               eval { $marc_record_obj = MARC::Record->new_from_usmarc($marc) }; # handle exceptions
+    my ( $marc, $xml, $biblionumber, $format ) = @_;
+
+    # global variables
+    my ( $marcxml, $record, $output );
+
+    # set the default path for intranet xslts
+    # differents xslts to process (OAIDC, SRWDC and RDFDC)
+    my $xsl = C4::Context->config('intrahtdocs') . '/prog/en/xslt/' .
+              C4::Context->preference('marcflavour') . 'slim2' . uc ( $format ) . '.xsl';
+
+    if ( defined $marc ) {
+        # no need to catch errors or warnings marc2marcxml do it instead
+        $marcxml = C4::Record::marc2marcxml( $marc );
+    } elsif ( not defined $xml and defined $biblionumber ) {
+        # get MARCXML biblio directly from biblioitems.marcxml without item information
+        $marcxml = C4::Biblio::GetXmlBiblio( $biblionumber );
+    } else {
+        $marcxml = $xml;
+    }
 
-               # conversion to MARC::Record object failed, populate $error
-               if ($@) {
-                       $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 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
-       $dcxmlfinal .= "<metadata
-  xmlns=\"http://example.org/myapp/\"
-  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
-  xsi:schemaLocation=\"http://example.org/myapp/ http://example.org/myapp/schema.xsd\"
-  xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
-  xmlns:dcterms=\"http://purl.org/dc/terms/\">";
-
-       foreach my $element ( $dcxml->elements() ) {
-                $dcxmlfinal.="<"."dc:".$element->name().">".$element->content()."</"."dc:".$element->name().">\n";
+    # only proceed if MARC21 or UNIMARC; else clause is executed if marcflavour set it to NORMARC
+    # generate MARC::Record object to see if not a marcxml record
+    unless ( C4::Context->preference('marcflavour') eq 'NORMARC' ) {
+        eval { $record = MARC::Record->new_from_xml(
+                         $marcxml,
+                         'UTF-8',
+                         C4::Context->preference('marcflavour')
+               );
+        };
+    } else {
+        eval { $record = MARC::Record->new_from_xml(
+                         $marcxml,
+                        'UTF-8',
+                        'MARC21'
+               );
+        };
+    }
+
+    # conversion to MARC::Record object failed
+    if ( $@ ) {
+        croak "Creation of MARC::Record object failed.";
+    } elsif ( $record->warnings() ) {
+        carp "Warnings encountered while processing ISO-2709 record.\n";
+        my @warnings = $record->warnings();
+        foreach my $warn (@warnings) {
+            carp "\t". $warn;
+        };
+    } elsif ( $record =~ /^MARC::Record/ ) { # if OK makes xslt transformation
+        my $xslt_engine = Koha::XSLT_Handler->new;
+        if ( $format =~ /oaidc|srwdc|rdfdc/ ) {
+            $output = $xslt_engine->transform( $marcxml, $xsl );
+        } else {
+            croak "The format argument ($format) not accepted.\n" .
+                  "Please pass a valid format (oaidc, srwdc, or rdfdc)\n";
+        }
+        my $err = $xslt_engine->err; # error number
+        my $errstr = $xslt_engine->errstr; # error message
+        if ( $err ) {
+            croak "Error when processing $errstr Error number: $err\n";
+        } else {
+            return $output;
+        }
     }
-       $dcxmlfinal .= "\n</metadata>";
-       return ($error,$dcxmlfinal);
 }
 
 =head2 marc2modsxml - Convert from ISO-2709 to MODS
index e66d3f2..39cac7c 100755 (executable)
@@ -50,8 +50,8 @@ if ($op eq "export") {
                 $marc = marc2bibtex($marc);
                 $format = "bibtex";
             }
-            elsif ($format =~ /dc/) {
-                ($error,$marc) = marc2dcxml($marc,1);
+            elsif ($format =~ /dc$/) {
+                $marc = marc2dcxml(undef, undef, $biblionumber, $format);
                 $format = "dublin-core.xml";
             }
             elsif ($format =~ /marc8/) {
index 3e604d2..68aeefa 100644 (file)
@@ -217,7 +217,7 @@ CAN_user_serials_create_subscription ) %]
     <button class="btn btn-small dropdown-toggle" data-toggle="dropdown"><i class="fa fa-download"></i> Save <span class="caret"></span></button>
     <ul class="dropdown-menu">
         <li><a href="/cgi-bin/koha/catalogue/export.pl?format=bibtex&amp;op=export&amp;bib=[% biblionumber %]">BIBTEX</a></li>
-        <li><a href="/cgi-bin/koha/catalogue/export.pl?format=dc&amp;op=export&amp;bib=[% biblionumber %]">Dublin Core (XML)</a></li>
+        <li><a href="#" data-toggle="modal" data-target="#exportModal_">Dublin Core</a></li>
         <li><a href="/cgi-bin/koha/catalogue/export.pl?format=marcxml&amp;op=export&amp;bib=[% biblionumber %]">MARCXML</a></li>
         <li><a href="/cgi-bin/koha/catalogue/export.pl?format=marc8&amp;op=export&amp;bib=[% biblionumber %]">MARC (non-Unicode/MARC-8)</a></li>
         <li><a href="/cgi-bin/koha/catalogue/export.pl?format=utf8&amp;op=export&amp;bib=[% biblionumber %]">MARC (Unicode/UTF-8)</a></li>
@@ -266,3 +266,31 @@ CAN_user_serials_create_subscription ) %]
 </form>
 </div>
 
+    <!--Modal for Dublin Core-->
+    <div class="modal hide" id="exportModal_" tabindex="-1" role="dialog" aria-labelledby="exportLabelexportModal_" aria-hidden="true">
+        <div class="modal-header">
+            <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">&times;</button>
+            <h3 id="exportLabelexportModal_">Exporting to Dublin Core...</h3>
+        </div>
+        <form method="get" action="/cgi-bin/koha/catalogue/export.pl">
+        <div class="modal-body">
+            <fieldset>
+                <input id="input-simple" type="radio" name="format" value="rdfdc">
+                <label for="input-simple">Simple DC-RDF</label>
+                <br>
+                <input id="input-oai" type="radio" name="format" value="oaidc" checked>
+                <label for="input-oai">OAI-DC</label>
+                <br>
+                <input id="input-srw" type="radio" name="format" value="srwdc">
+                <label for="input-srw">SRW-DC</label>
+                <br>
+            </fieldset>
+        </div>
+        <div class="modal-footer">
+            <button type="submit" class="btn">Export</button>
+            <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button>
+        </div>
+        <input type="hidden" name="op" value="export" />
+        <input type="hidden" name="bib" value="[% biblionumber %]" />
+        </form>
+    </div>
index 4fca8dd..e46428a 100644 (file)
@@ -1046,7 +1046,7 @@ function verify_images() {
       <th>Save Record</th>   </tr>
     <tr><td> Select download format:    <select name="format">
         <option value="mods">MODS (XML)</option>
-        <option value="dc">Dublin Core (XML)</option>
+        <option data-toggle="modal" data-target="#exportModal_">Dublin Core</option>
         <option value="marcxml">MARCXML</option>
         <option value="marc8">MARC (non-Unicode/MARC-8)</option>
         <option value="utf8">MARC (Unicode/UTF-8)</option>    </select>
@@ -1079,4 +1079,5 @@ function verify_images() {
 </div>
 [% END %]
 </div>
+
 [% INCLUDE 'intranet-bottom.inc' %]
index bde296d..63c09a3 100644 (file)
@@ -2,7 +2,7 @@
 [% INCLUDE 'doc-head-open.inc' %]
 <title>Koha &rsaquo; Catalog &rsaquo; Item details for [% title %] [% FOREACH subtitl IN subtitle %] [% subtitl.subfield %][% END %]</title>
 [% INCLUDE 'doc-head-close.inc' %]
-<style type="text/css">h3{padding-top: 1em; border-top: 2px solid #CCCCCC;}</style>
+<style type="text/css">h3{padding-top: 1em; border-top: 2px solid #CCCCCC;}#exportLabelexportModal_{border-top: 0px;}</style>
 [% INCLUDE 'browser-strings.inc' %]
 <!--[if lt IE 9]>
 <script type="text/javascript" src="[% interface %]/lib/shims/json2.min.js"></script>
index a4ef40e..b9972e7 100644 (file)
                     <a id="format" class="dropdown-toggle" data-toggle="dropdown" href="#">Save record <b class="caret"></b></a>
                         <ul class="dropdown-menu pull-right" role="menu" aria-labelledby="format">
                             [% FOREACH option IN export_options %]
+                                [% IF option == 'dc' %]
+                                    <li><a role="menuitem" href="#" data-toggle="modal" data-target="#exportModal_">Dublin Core</a></li>
+                                [% ELSE %]
                                 <li>
                                     <a role="menuitem" href="/cgi-bin/koha/opac-export.pl?op=export&amp;bib=[% biblionumber %]&amp;format=[% option %]">
                                         [% SWITCH option %]
                                             [% CASE 'bibtex' %]BIBTEX
-                                            [% CASE 'dc' %]Dublin Core (XML)
                                             [% CASE 'endnote' %]EndNote
                                             [% CASE 'marcxml' %]MARCXML
                                             [% CASE 'marc8' %]MARC (non-Unicode/MARC-8)
@@ -54,6 +56,7 @@
                                         [% END %]
                                     </a>
                                 </li>
+                                [% END %]
                             [% END %]
                         </ul>
                 </div>
index 4b3db89..92a033a 100644 (file)
 </div> <!-- / .container-fluid -->
 </div> <!-- / .main -->
 
+<!-- Dublin Core Modal Form -->
+<div class="modal hide" id="exportModal_" tabindex="-1" role="dialog" aria-labelledby="exportLabelexportModal_" aria-hidden="true">
+    <div class="modal-header">
+        <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">&times;</button>
+        <h3 class="modal-title" id="exportModalLabel">Exporting to Dublin Core...</h3>
+    </div>
+    <form method="get" action="/cgi-bin/koha/opac-export.pl">
+    <div class="modal-body">
+        <fieldset id="dc_fieldset">
+                <input id="input-simple" type="radio" name="format" value="rdfdc">
+                <label class="label_dc" for="input-simple">Simple DC-RDF</label>
+                <br>
+                <input id="input-oai" type="radio" name="format" value="oaidc">
+                <label class="label_dc" for="input-oai">OAI-DC</label>
+                <br>
+                <input id="input-srw" type="radio" name="format" value="srwdc">
+                <label class="label_dc" for="input-srw">SRW-DC</label>
+                <br>
+        <input type="hidden" name="op" value="export">
+        <input type="hidden" name="bib" value="[% biblionumber %]">
+        </fieldset>
+    </div>
+    <div class="modal-footer">
+        <button type="submit" class="btn">Export</button>
+        <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button>
+    </div>
+    </form>
+</div>
+
 [% INCLUDE 'opac-bottom.inc' %]
 
 [%# End of template %]
index 6da32e5..6aa7ba7 100644 (file)
@@ -2490,4 +2490,18 @@ a.reviewlink:visited {
     font-size: 90%;
 }
 
+#dc_fieldset {
+    border: 1px solid #dddddd;
+    border-width: 1px;
+    padding: 5px;
+    border-radius: 10px
+}
+
+.label_dc{
+    display: inline;
+    padding: 0px;
+    margin: 0px;
+    cursor: pointer;
+}
+
 @import "responsive.less";
index bf040db..c4ab83a 100755 (executable)
@@ -60,8 +60,8 @@ elsif ($format =~ /bibtex/) {
     $marc = marc2bibtex(C4::Biblio::GetMarcBiblio($biblionumber),$biblionumber);
     $format = 'bibtex';
 }
-elsif ($format =~ /dc/) {
-    ($error,$marc) = marc2dcxml($marc,1);
+elsif ($format =~ /dc$/) {
+    $marc = marc2dcxml(undef, undef, $biblionumber, $format);
     $format = "dublin-core.xml";
 }
 elsif ($format =~ /marc8/) {