From 39ed3dce71e535e16753413df7635c1942cc02cc Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Fri, 23 Jan 2015 07:11:36 -0500 Subject: [PATCH] Bug 12357: Enhancements to RIS and BibTeX exporting Some libraries would like to be able to add arbitrary fields to both the RIS and BibTeX citation formats that a record can be saved as from the staff intranet and public catalog. In addition, they would like to be able to override the default record type and use Koha's itemtype as the record type for those formats as well. Test Plan: 1) Apply this patch 2) Run updatedatabase.pl 3) Add the following to the new syspref RisExportAdditionalFields: TY: 942$c LC: 010$a NT: [501$a, 505$g] 4) Find or create a record with an 010$a (lccn) field, a 501$a field, a 942$c field, and multiple 505$g fields. 5) Locate the record in the catalog, choose "Save" and select RIS 6) Inspect the downloaded file, note the replaced TY field, the LC field, and multiple NT fields 7) Add the following to the new syspref BibtexExportAdditionalFields: '@': 942$c lccn: 010$a notes: [501$a, 505$g] 9) Using the previously selected record, choose "Save" and select BIBTEX 10) Inspect the downloaded file, note the lccn, the multiple note fields, and the new record type value Signed-off-by: Frederic Demians Signed-off-by: Bernardo Gonzalez Kriegel Signed-off-by: Jonathan Druart Signed-off-by: Tomas Cohen Arazi --- C4/Record.pm | 61 ++++++++++-- C4/Ris.pm | 97 ++++++++++++++----- .../data/mysql/atomicupdate/bug_12357.sql | 5 + installer/data/mysql/sysprefs.sql | 2 + .../admin/preferences/cataloguing.pref | 23 +++++ 5 files changed, 157 insertions(+), 31 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_12357.sql diff --git a/C4/Record.pm b/C4/Record.pm index 5d894fa85e..2e6ed98863 100644 --- a/C4/Record.pm +++ b/C4/Record.pm @@ -35,6 +35,7 @@ use C4::XSLT (); use YAML; #marcrecords2csv use Template; use Text::CSV::Encoded; #marc2csv +use Koha::SimpleMARC qw(read_field); use vars qw($VERSION @ISA @EXPORT); @@ -327,8 +328,8 @@ sub marc2endnote { } my $fields = { DB => C4::Context->preference("LibraryName"), - Title => $marc_rec_obj->title(), - Author => $marc_rec_obj->author(), + Title => $marc_rec_obj->title(), + Author => $marc_rec_obj->author(), Publisher => $f710a, City => $f260a, Year => $marc_rec_obj->publication_date, @@ -346,7 +347,7 @@ sub marc2endnote { $template.="AB - Abstract\n" if $abstract; my ($text, $errmsg) = $style->format($template, $fields); return ($text); - + } =head2 marc2csv - Convert several records from UNIMARC to CSV @@ -640,7 +641,7 @@ sub changeEncoding { my $error; unless($flavour) {$flavour = C4::Context->preference("marcflavour")}; unless($to_encoding) {$to_encoding = "UTF-8"}; - + # ISO-2709 Record (MARC21 or UNIMARC) if (lc($format) =~ /^marc$/o) { # if we're converting encoding of an ISO2709 file, we need to roundtrip through XML @@ -651,7 +652,7 @@ sub changeEncoding { unless ($error) { ($error,$newrecord) = marcxml2marc($marcxml,$to_encoding,$flavour); } - + # MARCXML Record } elsif (lc($format) =~ /^marcxml$/o) { # MARCXML Record my $marc; @@ -749,14 +750,60 @@ sub marc2bibtex { ); } - $tex .= "\@book{"; + my $BibtexExportAdditionalFields = C4::Context->preference('BibtexExportAdditionalFields'); + my $additional_fields; + if ($BibtexExportAdditionalFields) { + $BibtexExportAdditionalFields = "$BibtexExportAdditionalFields\n\n"; + $additional_fields = eval { YAML::Load($BibtexExportAdditionalFields); }; + if ($@) { + warn "Unable to parse BibtexExportAdditionalFields : $@"; + $additional_fields = undef; + } + } + + if ( $additional_fields && $additional_fields->{'@'} ) { + my ( $f, $sf ) = split( /\$/, $additional_fields->{'@'} ); + my ( $type ) = read_field( { record => $record, field => $f, subfield => $sf, field_numbers => [1] } ); + + if ($type) { + $tex .= '@' . $type . '{'; + } + else { + $tex .= "\@book{"; + } + } + else { + $tex .= "\@book{"; + } + my @elt; for ( my $i = 0 ; $i < scalar( @bh ) ; $i = $i + 2 ) { next unless $bh[$i+1]; push @elt, qq|\t$bh[$i] = {$bh[$i+1]}|; } $tex .= join(",\n", $id, @elt); - $tex .= "\n}\n"; + $tex .= "\n"; + + if ($additional_fields) { + foreach my $bibtex_tag ( keys %$additional_fields ) { + next if $bibtex_tag eq '@'; + + my @fields = + ref( $additional_fields->{$bibtex_tag} ) eq 'ARRAY' + ? @{ $additional_fields->{$bibtex_tag} } + : $additional_fields->{$bibtex_tag}; + + for my $tag (@fields) { + my ( $f, $sf ) = split( /\$/, $tag ); + my @values = read_field( { record => $record, field => $f, subfield => $sf } ); + foreach my $v (@values) { + $tex .= qq(\t$bibtex_tag = {$v}\n); + } + } + } + } + + $tex .= "}\n"; return $tex; } diff --git a/C4/Ris.pm b/C4/Ris.pm index 0a0f181ca5..6443eb611e 100644 --- a/C4/Ris.pm +++ b/C4/Ris.pm @@ -59,12 +59,14 @@ package C4::Ris; # # -#use strict; -#use warnings; +use Modern::Perl; use List::MoreUtils qw/uniq/; use vars qw($VERSION @ISA @EXPORT); +use C4::Biblio qw(GetMarcSubfieldStructureFromKohaField); +use Koha::SimpleMARC qw(read_field); + # set the version for version checking $VERSION = 3.07.00.049; @@ -76,6 +78,11 @@ $VERSION = 3.07.00.049; &marc2ris ); +our $utf; +our $intype; +our $marcprint; +our $protoyear; + =head1 marc2bibtex - Convert from UNIMARC to RIS @@ -101,25 +108,47 @@ sub marc2ris { close STDOUT; open STDOUT,'>', \$outvar; + ## First we should check the character encoding. This may be + ## MARC-8 or UTF-8. The former is indicated by a blank, the latter + ## by 'a' at position 09 (zero-based) of the leader + my $leader = $record->leader(); + if ( $intype eq "marc21" ) { + if ( $leader =~ /^.{9}a/ ) { + print "---\r\nUTF-8 data\r\n" if $marcprint; + $utf = 1; + } + else { + print "---\r\nMARC-8 data\r\n" if $marcprint; + } + } + ## else: other MARC formats do not specify the character encoding + ## we assume it's *not* UTF-8 + + my $RisExportAdditionalFields = C4::Context->preference('RisExportAdditionalFields'); + my $ris_additional_fields; + if ($RisExportAdditionalFields) { + $RisExportAdditionalFields = "$RisExportAdditionalFields\n\n"; + $ris_additional_fields = eval { YAML::Load($RisExportAdditionalFields); }; + if ($@) { + warn "Unable to parse RisExportAdditionalFields : $@"; + $ris_additional_fields = undef; + } + } - ## First we should check the character encoding. This may be - ## MARC-8 or UTF-8. The former is indicated by a blank, the latter - ## by 'a' at position 09 (zero-based) of the leader - my $leader = $record->leader(); - if ($intype eq "marc21") { - if ($leader =~ /^.{9}a/) { - print "---\r\nUTF-8 data\r\n" if $marcprint; - $utf = 1; - } - else { - print "---\r\nMARC-8 data\r\n" if $marcprint; - } - } - ## else: other MARC formats do not specify the character encoding - ## we assume it's *not* UTF-8 - - ## start RIS dataset - &print_typetag($leader); + ## start RIS dataset + if ( $ris_additional_fields && $ris_additional_fields->{TY} ) { + my ( $f, $sf ) = split( /\$/, $ris_additional_fields->{TY} ); + my ( $type ) = read_field( { record => $record, field => $f, subfield => $sf, field_numbers => [1] } ); + if ($type) { + print "TY - $type\r\n"; + } + else { + &print_typetag($leader); + } + } + else { + &print_typetag($leader); + } ## retrieve all author fields and collect them in a list my @author_fields; @@ -285,6 +314,25 @@ sub marc2ris { print_uri($record->field('856')); } + if ($ris_additional_fields) { + foreach my $ris_tag ( keys %$ris_additional_fields ) { + next if $ris_tag eq 'TY'; + + my @fields = + ref( $ris_additional_fields->{$ris_tag} ) eq 'ARRAY' + ? @{ $ris_additional_fields->{$ris_tag} } + : $ris_additional_fields->{$ris_tag}; + + for my $tag (@fields) { + my ( $f, $sf ) = split( /\$/, $tag ); + my @values = read_field( { record => $record, field => $f, subfield => $sf } ); + foreach my $v (@values) { + print "$ris_tag - $v\r\n"; + } + } + } + } + ## end RIS dataset print "ER - \r\n"; @@ -497,6 +545,7 @@ sub print_title { my $clean_title = $titlefield->subfield('a'); my $clean_subtitle = $titlefield->subfield('b'); +$clean_subtitle ||= q{}; $clean_title =~ s% *[/:;.]$%%; $clean_subtitle =~ s%^ *(.*) *[/:;.]$%$1%; @@ -777,7 +826,7 @@ sub get_keywords { } else { ## retrieve all available subfields - @kwsubfields = $kwfield->subfields(); + my @kwsubfields = $kwfield->subfields(); ## loop over all available subfield tuples foreach my $kwtuple (@kwsubfields) { @@ -891,9 +940,9 @@ sub pool_subx { ## loop over all notefields foreach my $notefield (@notefields) { - if ($notefield != undef) { + if (defined $notefield) { ## retrieve all available subfield tuples - @notesubfields = $notefield->subfields(); + my @notesubfields = $notefield->subfields(); ## loop over all subfield tuples foreach my $notetuple (@notesubfields) { @@ -967,7 +1016,7 @@ sub charconv { ## return unaltered if already utf-8 return @_; } - elsif ($uniout eq "t") { + elsif (my $uniout eq "t") { ## convert to utf-8 return marc8_to_utf8("@_"); } diff --git a/installer/data/mysql/atomicupdate/bug_12357.sql b/installer/data/mysql/atomicupdate/bug_12357.sql new file mode 100644 index 0000000000..b9e3e70844 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_12357.sql @@ -0,0 +1,5 @@ +INSERT INTO systempreferences (variable,value,options,explanation,type) +VALUES ('RisExportAdditionalFields', '', NULL , 'Define additional RIS tags to export from MARC records in YAML format as an associative array with either a marc tag/subfield combination as the value, or a list of tag/subfield combinations.', 'textarea'); + +INSERT INTO systempreferences (variable,value,options,explanation,type) +VALUES ('BibtexExportAdditionalFields', '', NULL , 'Define additional BibTex tags to export from MARC records in YAML format as an associative array with either a marc tag/subfield combination as the value, or a list of tag/subfield combinations.', 'textarea'); diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index 65689673de..88a1f5f44e 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -65,6 +65,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('BasketConfirmations','1','always ask for confirmation.|do not ask for confirmation.','When closing or reopening a basket,','Choice'), ('BiblioAddsAuthorities','0',NULL,'If ON, adding a new biblio will check for an existing authority record and create one on the fly if one doesn\'t exist','YesNo'), ('BiblioDefaultView','normal','normal|marc|isbd','Choose the default detail view in the catalog; choose between normal, marc or isbd','Choice'), +('BibtexExportAdditionalFields', '', NULL , 'Define additional BibTex tags to export from MARC records in YAML format as an associative array with either a marc tag/subfield combination as the value, or a list of tag/subfield combinations.', 'textarea'), ('BlockExpiredPatronOpacActions','1',NULL,'Set whether an expired patron can perform opac actions such as placing holds or renew books, can be overridden on a per patron-type basis','YesNo'), ('BlockReturnOfWithdrawnItems','1','0','If enabled, items that are marked as withdrawn cannot be returned.','YesNo'), ('BorrowerMandatoryField','surname|cardnumber',NULL,'Choose the mandatory fields for a patron\'s account','free'), @@ -373,6 +374,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('ReturnLog','1',NULL,'If ON, enables the circulation (returns) log','YesNo'), ('ReturnToShelvingCart','0','','If set, when any item is \'checked in\', it\'s location code will be changed to CART.','YesNo'), ('reviewson','1','','If ON, enables patron reviews of bibliographic records in the OPAC','YesNo'), +('RisExportAdditionalFields', '', NULL , 'Define additional RIS tags to export from MARC records in YAML format as an associative array with either a marc tag/subfield combination as the value, or a list of tag/subfield combinations.', 'textarea'), ('RoutingListAddReserves','1','','If ON the patrons on routing lists are automatically added to holds on the issue.','YesNo'), ('RoutingListNote','To change this note edit RoutingListNote system preference.','70|10','Define a note to be shown on all routing lists','Textarea'), ('RoutingSerials','1',NULL,'If ON, serials routing is enabled','YesNo'), diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref index bc35aad8a1..703e17ce47 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref @@ -215,3 +215,26 @@ Cataloging: yes: "do" no: "don't" - attempt to match aggressively by trying all variations of the ISBNs in the imported record as a phrase in the ISBN fields of already cataloged records. Note that this preference has no effect if UseQueryParser is on. + Exporting: + - + - Include following fields when exporting BibTeX, + - pref: BibtexExportAdditionalFields + type: textarea + - "Use one line per tag in the format BT_TAG: TAG$SUBFIELD ( e.g. lccn: 010$a )" + - "
" + - "To specificy multiple marc tags/subfields as targets for a repeating BibTex tag, use the following format: BT_TAG: [TAG2$SUBFIELD1, TAG2$SUBFIELD2] ( e.g. notes: [501$a, 505$g] )" + - "
" + - "All values of repeating tags and subfields will be printed with the given BibTeX tag." + - "
" + - "Use '@' ( with quotes ) as the BT_TAG to replace the bibtex record type with a field value of your choosing." + - + - Include following fields when exporting RIS, + - pref: RisExportAdditionalFields + type: textarea + - "Use one line per tag in the format RIS_TAG: TAG$SUBFIELD ( e.g. LC: 010$a )" + - "
" + - "To specificy multiple marc tags/subfields as targets for a repeating RIS tag, use the following format: RIS_TAG: [TAG2$SUBFIELD1, TAG2$SUBFIELD2] ( e.g. NT: [501$a, 505$g] )" + - "
" + - "All values of repeating tags and subfields will be printed with the given RIS tag." + - "
" + - "Use of TY ( record type ) as a key will replace the default TY with the field value of your choosing." -- 2.39.5