Bug 16198: Fix regression in OPAC suggestions
[koha.git] / C4 / Ris.pm
bloba1db07f0becffffd25c61cc412df916de96b1aa3
1 package C4::Ris;
3 # Original script :
4 ## marc2ris: converts MARC21 and UNIMARC datasets to RIS format
5 ## See comments below for compliance with other MARC dialects
6 ##
7 ## usage: perl marc2ris < infile.marc > outfile.ris
8 ##
9 ## Dependencies: perl 5.6.0 or later
10 ## MARC::Record
11 ## MARC::Charset
13 ## markus@mhoenicka.de 2002-11-16
15 ## This program is free software; you can redistribute it and/or modify
16 ## it under the terms of the GNU General Public License as published by
17 ## the Free Software Foundation; either version 2 of the License, or
18 ## (at your option) any later version.
19 ##
20 ## This program is distributed in the hope that it will be useful,
21 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ## GNU General Public License for more details.
25 ## You should have received a copy of the GNU General Public License
26 ## along with this program; if not, write to the Free Software
27 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 ## Some background about MARC as understood by this script
30 ## The default input format used in this script is MARC21, which
31 ## superseded USMARC and CANMARC. The specification can be found at:
32 ## http://lcweb.loc.gov/marc/
33 ## UNIMARC follows the specification at:
34 ## http://www.ifla.org/VI/3/p1996-1/sec-uni.htm
35 ## UKMARC support is a bit shaky because there is no specification available
36 ## for free. The wisdom used in this script was taken from a PDF document
37 ## comparing UKMARC to MARC21 found at:
38 ## www.bl.uk/services/bibliographic/marcchange.pdf
41 # Modified 2008 by BibLibre for Koha
42 # Modified 2011 by Catalyst
43 # Modified 2011 by Equinox Software, Inc.
45 # This file is part of Koha.
47 # Koha is free software; you can redistribute it and/or modify it
48 # under the terms of the GNU General Public License as published by
49 # the Free Software Foundation; either version 3 of the License, or
50 # (at your option) any later version.
52 # Koha is distributed in the hope that it will be useful, but
53 # WITHOUT ANY WARRANTY; without even the implied warranty of
54 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55 # GNU General Public License for more details.
57 # You should have received a copy of the GNU General Public License
58 # along with Koha; if not, see <http://www.gnu.org/licenses>.
62 use Modern::Perl;
64 use List::MoreUtils qw/uniq/;
65 use vars qw(@ISA @EXPORT);
67 use C4::Biblio qw(GetMarcSubfieldStructureFromKohaField);
68 use Koha::SimpleMARC qw(read_field);
71 @ISA = qw(Exporter);
73 # only export API methods
75 @EXPORT = qw(
76 &marc2ris
79 our $utf;
80 our $intype;
81 our $marcprint;
82 our $protoyear;
85 =head1 marc2bibtex - Convert from UNIMARC to RIS
87 my ($ris) = marc2ris($record);
89 Returns a RIS scalar
91 C<$record> - a MARC::Record object
93 =cut
95 sub marc2ris {
96 my ($record) = @_;
97 my $output;
99 my $marcflavour = C4::Context->preference("marcflavour");
100 $intype = lc($marcflavour);
101 my $marcprint = 0; # Debug flag;
103 # Let's redirect stdout
104 open my $oldout, ">&STDOUT";
105 my $outvar;
106 close STDOUT;
107 open STDOUT,'>:encoding(utf8)', \$outvar;
109 ## First we should check the character encoding. This may be
110 ## MARC-8 or UTF-8. The former is indicated by a blank, the latter
111 ## by 'a' at position 09 (zero-based) of the leader
112 my $leader = $record->leader();
113 if ( $intype eq "marc21" ) {
114 if ( $leader =~ /^.{9}a/ ) {
115 print "<marc>---\r\n<marc>UTF-8 data\r\n" if $marcprint;
116 $utf = 1;
118 else {
119 print "<marc>---\r\n<marc>MARC-8 data\r\n" if $marcprint;
122 ## else: other MARC formats do not specify the character encoding
123 ## we assume it's *not* UTF-8
125 my $RisExportAdditionalFields = C4::Context->preference('RisExportAdditionalFields');
126 my $ris_additional_fields;
127 if ($RisExportAdditionalFields) {
128 $RisExportAdditionalFields = "$RisExportAdditionalFields\n\n";
129 $ris_additional_fields = eval { YAML::Load($RisExportAdditionalFields); };
130 if ($@) {
131 warn "Unable to parse RisExportAdditionalFields : $@";
132 $ris_additional_fields = undef;
136 ## start RIS dataset
137 if ( $ris_additional_fields && $ris_additional_fields->{TY} ) {
138 my ( $f, $sf ) = split( /\$/, $ris_additional_fields->{TY} );
139 my ( $type ) = read_field( { record => $record, field => $f, subfield => $sf, field_numbers => [1] } );
140 if ($type) {
141 print "TY - $type\r\n";
143 else {
144 &print_typetag($leader);
147 else {
148 &print_typetag($leader);
151 ## retrieve all author fields and collect them in a list
152 my @author_fields;
154 if ($intype eq "unimarc") {
155 ## Fields 700, 701, and 702 can contain author names
156 @author_fields = ($record->field('700'), $record->field('701'), $record->field('702'));
158 else { ## marc21, ukmarc
159 ## Field 100 sometimes carries main author
160 ## Field(s) 700 carry added entries - personal names
161 @author_fields = ($record->field('100'), $record->field('700'));
164 ## loop over all author fields
165 foreach my $field (@author_fields) {
166 if (length($field)) {
167 my $author = &get_author($field);
168 print "AU - ",&charconv($author),"\r\n";
172 # ToDo: should we specify anonymous as author if we didn't find
173 # one? or use one of the corporate/meeting names below?
175 ## add corporate names or meeting names as editors ??
176 my @editor_fields;
178 if ($intype eq "unimarc") {
179 ## Fields 710, 711, and 712 can carry corporate names
180 ## Field(s) 720, 721, 722, 730 have additional candidates
181 @editor_fields = ($record->field('710'), $record->field('711'), $record->field('712'), $record->field('720'), $record->field('721'), $record->field('722'), $record->field('730'));
183 else { ## marc21, ukmarc
184 ## Fields 110 and 111 carry the main entries - corporate name and
185 ## meeting name, respectively
186 ## Field(s) 710, 711 carry added entries - personal names
187 @editor_fields = ($record->field('110'), $record->field('111'), $record->field('710'), $record->field('711'));
190 ## loop over all editor fields
191 foreach my $field (@editor_fields) {
192 if (length($field)) {
193 my $editor = &get_editor($field);
194 print "ED - ",&charconv($editor),"\r\n";
198 ## get info from the title field
199 if ($intype eq "unimarc") {
200 &print_title($record->field('200'));
202 else { ## marc21, ukmarc
203 &print_title($record->field('245'));
206 ## series title
207 if ($intype eq "unimarc") {
208 &print_stitle($record->field('225'));
210 else { ## marc21, ukmarc
211 &print_stitle($record->field('490'));
214 ## ISBN/ISSN
215 if ($intype eq "unimarc") {
216 &print_isbn($record->field('010'));
217 &print_issn($record->field('011'));
219 elsif ($intype eq "ukmarc") {
220 &print_isbn($record->field('021'));
221 ## this is just an assumption
222 &print_issn($record->field('022'));
224 else { ## assume marc21
225 &print_isbn($record->field('020'));
226 &print_issn($record->field('022'));
229 if ($intype eq "marc21") {
230 &print_loc_callno($record->field('050'));
231 &print_dewey($record->field('082'));
233 ## else: unimarc, ukmarc do not seem to store call numbers?
235 ## publication info
236 if ($intype eq "unimarc") {
237 &print_pubinfo($record->field('210'));
239 else { ## marc21, ukmarc
240 if ($record->field('264')) {
241 &print_pubinfo($record->field('264'));
243 else {
244 &print_pubinfo($record->field('260'));
248 ## 6XX fields contain KW candidates. We add all of them to a
250 my @field_list;
251 if ($intype eq "unimarc") {
252 @field_list = ('600', '601', '602', '604', '605', '606','607', '608', '610', '615', '620', '660', '661', '670', '675', '676', '680', '686');
253 } elsif ($intype eq "ukmarc") {
254 @field_list = ('600', '610', '611', '630', '650', '651','653', '655', '660', '661', '668', '690', '691', '692', '695');
255 } else { ## assume marc21
256 @field_list = ('600', '610', '611', '630', '650', '651','653', '654', '655', '656', '657', '658');
259 my @kwpool;
260 for my $f ( @field_list ) {
261 my @fields = $record->field($f);
262 push @kwpool, ( get_keywords("$f",$record->field($f)) );
265 # Remove duplicate
266 @kwpool = uniq @kwpool;
268 for my $kw ( @kwpool ) {
269 print "KW - ", &charconv($kw), "\r\n";
272 ## 5XX have various candidates for notes and abstracts. We pool
273 ## all notes-like stuff in one list.
274 my @notepool;
276 ## these fields have notes candidates
277 if ($intype eq "unimarc") {
278 foreach ('300', '301', '302', '303', '304', '305', '306', '307', '308', '310', '311', '312', '313', '314', '315', '316', '317', '318', '320', '321', '322', '323', '324', '325', '326', '327', '328', '332', '333', '336', '337', '345') {
279 &pool_subx(\@notepool, $_, $record->field($_));
282 elsif ($intype eq "ukmarc") {
283 foreach ('500', '501', '502', '503', '504', '505', '506', '508', '514', '515', '516', '521', '524', '525', '528', '530', '531', '532', '533', '534', '535', '537', '538', '540', '541', '542', '544', '554', '555', '556', '557', '561', '563', '580', '583', '584', '586') {
284 &pool_subx(\@notepool, $_, $record->field($_));
287 else { ## assume marc21
288 foreach ('500', '501', '502', '504', '505', '506', '507', '508', '510', '511', '513', '514', '515', '516', '518', '521', '522', '524', '525', '526', '530', '533', '534', '535') {
289 &pool_subx(\@notepool, $_, $record->field($_));
293 my $allnotes = join "; ", @notepool;
295 if (length($allnotes) > 0) {
296 print "N1 - ", &charconv($allnotes), "\r\n";
299 ## 320/520 have the abstract
300 if ($intype eq "unimarc") {
301 &print_abstract($record->field('320'));
303 elsif ($intype eq "ukmarc") {
304 &print_abstract($record->field('512'), $record->field('513'));
306 else { ## assume marc21
307 &print_abstract($record->field('520'));
310 # 856u has the URI
311 if ($record->field('856')) {
312 print_uri($record->field('856'));
315 if ($ris_additional_fields) {
316 foreach my $ris_tag ( keys %$ris_additional_fields ) {
317 next if $ris_tag eq 'TY';
319 my @fields =
320 ref( $ris_additional_fields->{$ris_tag} ) eq 'ARRAY'
321 ? @{ $ris_additional_fields->{$ris_tag} }
322 : $ris_additional_fields->{$ris_tag};
324 for my $tag (@fields) {
325 my ( $f, $sf ) = split( /\$/, $tag );
326 my @values = read_field( { record => $record, field => $f, subfield => $sf } );
327 foreach my $v (@values) {
328 print "$ris_tag - $v\r\n";
334 ## end RIS dataset
335 print "ER - \r\n";
337 # Let's re-redirect stdout
338 close STDOUT;
339 open STDOUT, ">&", $oldout;
341 return $outvar;
346 ##********************************************************************
347 ## print_typetag(): prints the first line of a RIS dataset including
348 ## the preceding newline
349 ## Argument: the leader of a MARC dataset
350 ## Returns: the value at leader position 06
351 ##********************************************************************
352 sub print_typetag {
353 my ($leader)= @_;
354 ## the keys of typehash are the allowed values at position 06
355 ## of the leader of a MARC record, the values are the RIS types
356 ## that might appropriately represent these types.
357 my %ustypehash = (
358 "a" => "BOOK",
359 "c" => "MUSIC",
360 "d" => "MUSIC",
361 "e" => "MAP",
362 "f" => "MAP",
363 "g" => "ADVS",
364 "i" => "SOUND",
365 "j" => "SOUND",
366 "k" => "ART",
367 "m" => "DATA",
368 "o" => "GEN",
369 "p" => "GEN",
370 "r" => "ART",
371 "t" => "GEN",
374 my %unitypehash = (
375 "a" => "BOOK",
376 "b" => "BOOK",
377 "c" => "MUSIC",
378 "d" => "MUSIC",
379 "e" => "MAP",
380 "f" => "MAP",
381 "g" => "ADVS",
382 "i" => "SOUND",
383 "j" => "SOUND",
384 "k" => "ART",
385 "l" => "ELEC",
386 "m" => "ADVS",
387 "r" => "ART",
390 ## The type of a MARC record is found at position 06 of the leader
391 my $typeofrecord = substr($leader, 6, 1);
393 ## ToDo: for books, field 008 positions 24-27 might have a few more
394 ## hints
396 my %typehash;
398 ## the ukmarc here is just a guess
399 if ($intype eq "marc21" || $intype eq "ukmarc") {
400 %typehash = %ustypehash;
402 elsif ($intype eq "unimarc") {
403 %typehash = %unitypehash;
405 else {
406 ## assume MARC21 as default
407 %typehash = %ustypehash;
410 if (!exists $typehash{$typeofrecord}) {
411 print "TY - BOOK\r\n"; ## most reasonable default
412 warn ("no type found - assume BOOK") if $marcprint;
414 else {
415 print "TY - $typehash{$typeofrecord}\r\n";
418 ## use $typeofrecord as the return value, just in case
419 $typeofrecord;
422 ##********************************************************************
423 ## normalize_author(): normalizes an authorname
424 ## Arguments: authorname subfield a
425 ## authorname subfield b
426 ## authorname subfield c
427 ## name type if known: 0=direct order
428 ## 1=only surname or full name in
429 ## inverted order
430 ## 3=family, clan, dynasty name
431 ## Returns: the normalized authorname
432 ##********************************************************************
433 sub normalize_author {
434 my($rawauthora, $rawauthorb, $rawauthorc, $nametype) = @_;
436 if ($nametype == 0) {
437 # ToDo: convert every input to Last[,(F.|First)[ (M.|Middle)[,Suffix]]]
438 warn("name >>$rawauthora<< in direct order - leave as is") if $marcprint;
439 return $rawauthora;
441 elsif ($nametype == 1) {
442 ## start munging subfield a (the real name part)
443 ## remove spaces after separators
444 $rawauthora =~ s%([,.]+) *%$1%g;
446 ## remove trailing separators after spaces
447 $rawauthora =~ s% *[,;:/]*$%%;
449 ## remove periods after a non-abbreviated name
450 $rawauthora =~ s%(\w{2,})\.%$1%g;
452 ## start munging subfield b (something like the suffix)
453 ## remove trailing separators after spaces
454 $rawauthorb =~ s% *[,;:/]*$%%;
456 ## we currently ignore subfield c until someone complains
457 if (length($rawauthorb) > 0) {
458 return join ", ", ($rawauthora, $rawauthorb);
460 else {
461 return $rawauthora;
464 elsif ($nametype == 3) {
465 return $rawauthora;
469 ##********************************************************************
470 ## get_author(): gets authorname info from MARC fields 100, 700
471 ## Argument: field (100 or 700)
472 ## Returns: an author string in the format found in the record
473 ##********************************************************************
474 sub get_author {
475 my ($authorfield) = @_;
476 my ($indicator);
478 ## the sequence of the name parts is encoded either in indicator
479 ## 1 (marc21) or 2 (unimarc)
480 if ($intype eq "unimarc") {
481 $indicator = 2;
483 else { ## assume marc21
484 $indicator = 1;
487 print "<marc>:Author(Ind$indicator): ", $authorfield->indicator("$indicator"),"\r\n" if $marcprint;
488 print "<marc>:Author(\$a): ", $authorfield->subfield('a'),"\r\n" if $marcprint;
489 print "<marc>:Author(\$b): ", $authorfield->subfield('b'),"\r\n" if $marcprint;
490 print "<marc>:Author(\$c): ", $authorfield->subfield('c'),"\r\n" if $marcprint;
491 print "<marc>:Author(\$h): ", $authorfield->subfield('h'),"\r\n" if $marcprint;
492 if ($intype eq "ukmarc") {
493 my $authorname = $authorfield->subfield('a') . "," . $authorfield->subfield('h');
494 normalize_author($authorname, $authorfield->subfield('b'), $authorfield->subfield('c'), $authorfield->indicator("$indicator"));
496 else {
497 normalize_author($authorfield->subfield('a') // '', $authorfield->subfield('b') // '', $authorfield->subfield('c') // '', $authorfield->indicator("$indicator"));
501 ##********************************************************************
502 ## get_editor(): gets editor info from MARC fields 110, 111, 710, 711
503 ## Argument: field (110, 111, 710, or 711)
504 ## Returns: an author string in the format found in the record
505 ##********************************************************************
506 sub get_editor {
507 my ($editorfield) = @_;
509 if (!$editorfield) {
510 return;
512 else {
513 print "<marc>Editor(\$a): ", $editorfield->subfield('a'),"\r\n" if $marcprint;
514 print "<marc>Editor(\$b): ", $editorfield->subfield('b'),"\r\n" if $marcprint;
515 print "<marc>editor(\$c): ", $editorfield->subfield('c'),"\r\n" if $marcprint;
516 return $editorfield->subfield('a');
520 ##********************************************************************
521 ## print_title(): gets info from MARC field 245
522 ## Arguments: field (245)
523 ## Returns:
524 ##********************************************************************
525 sub print_title {
526 my ($titlefield) = @_;
527 if (!$titlefield) {
528 print "<marc>empty title field (245)\r\n" if $marcprint;
529 warn("empty title field (245)") if $marcprint;
531 else {
532 print "<marc>Title(\$a): ",$titlefield->subfield('a'),"\r\n" if $marcprint;
533 print "<marc>Title(\$b): ",$titlefield->subfield('b'),"\r\n" if $marcprint;
534 print "<marc>Title(\$c): ",$titlefield->subfield('c'),"\r\n" if $marcprint;
536 ## The title is usually written in a very odd notation. The title
537 ## proper ($a) often ends with a space followed by a separator like
538 ## a slash or a colon. The subtitle ($b) doesn't start with a space
539 ## so simple concatenation looks odd. We have to conditionally remove
540 ## the separator and make sure there's a space between title and
541 ## subtitle
543 my $clean_title = $titlefield->subfield('a');
545 my $clean_subtitle = $titlefield->subfield('b');
546 $clean_subtitle ||= q{};
547 $clean_title =~ s% *[/:;.]$%%;
548 $clean_subtitle =~ s%^ *(.*) *[/:;.]$%$1%;
550 if (length($clean_title) > 0
551 || (length($clean_subtitle) > 0 && $intype ne "unimarc")) {
552 print "TI - ", &charconv($clean_title);
554 ## subfield $b is relevant only for marc21/ukmarc
555 if (length($clean_subtitle) > 0 && $intype ne "unimarc") {
556 print ": ",&charconv($clean_subtitle);
558 print "\r\n";
561 ## The statement of responsibility is just this: horrors. There is
562 ## no formal definition how authors, editors and the like should
563 ## be written and designated. The field is free-form and resistant
564 ## to all parsing efforts, so this information is lost on me
568 ##********************************************************************
569 ## print_stitle(): prints info from series title field
570 ## Arguments: field
571 ## Returns:
572 ##********************************************************************
573 sub print_stitle {
574 my ($titlefield) = @_;
576 if (!$titlefield) {
577 print "<marc>empty series title field\r\n" if $marcprint;
579 else {
580 print "<marc>Series title(\$a): ",$titlefield->subfield('a'),"\r\n" if $marcprint;
581 my $clean_title = $titlefield->subfield('a');
583 $clean_title =~ s% *[/:;.]$%%;
585 if (length($clean_title) > 0) {
586 print "T2 - ", &charconv($clean_title),"\r\n";
589 if ($intype eq "unimarc") {
590 print "<marc>Series vol(\$v): ",$titlefield->subfield('v'),"\r\n" if $marcprint;
591 if (length($titlefield->subfield('v')) > 0) {
592 print "VL - ", &charconv($titlefield->subfield('v')),"\r\n";
598 ##********************************************************************
599 ## print_isbn(): gets info from MARC field 020
600 ## Arguments: field (020)
601 ##********************************************************************
602 sub print_isbn {
603 my($isbnfield) = @_;
605 if (!$isbnfield || length ($isbnfield->subfield('a')) == 0) {
606 print "<marc>no isbn found (020\$a)\r\n" if $marcprint;
607 warn("no isbn found") if $marcprint;
609 else {
610 if (length ($isbnfield->subfield('a')) < 10) {
611 print "<marc>truncated isbn (020\$a)\r\n" if $marcprint;
612 warn("truncated isbn") if $marcprint;
615 my $isbn = $isbnfield->subfield('a');
616 print "SN - ", &charconv($isbn), "\r\n";
620 ##********************************************************************
621 ## print_issn(): gets info from MARC field 022
622 ## Arguments: field (022)
623 ##********************************************************************
624 sub print_issn {
625 my($issnfield) = @_;
627 if (!$issnfield || length ($issnfield->subfield('a')) == 0) {
628 print "<marc>no issn found (022\$a)\r\n" if $marcprint;
629 warn("no issn found") if $marcprint;
631 else {
632 if (length ($issnfield->subfield('a')) < 9) {
633 print "<marc>truncated issn (022\$a)\r\n" if $marcprint;
634 warn("truncated issn") if $marcprint;
637 my $issn = substr($issnfield->subfield('a'), 0, 9);
638 print "SN - ", &charconv($issn), "\r\n";
643 # print_uri() prints info from 856 u
645 sub print_uri {
646 my @f856s = @_;
648 foreach my $f856 (@f856s) {
649 if (my $uri = $f856->subfield('u')) {
650 print "UR - ", charconv($uri), "\r\n";
655 ##********************************************************************
656 ## print_loc_callno(): gets info from MARC field 050
657 ## Arguments: field (050)
658 ##********************************************************************
659 sub print_loc_callno {
660 my($callnofield) = @_;
662 if (!$callnofield || length ($callnofield->subfield('a')) == 0) {
663 print "<marc>no LOC call number found (050\$a)\r\n" if $marcprint;
664 warn("no LOC call number found") if $marcprint;
666 else {
667 print "AV - ", &charconv($callnofield->subfield('a')), " ", &charconv($callnofield->subfield('b')), "\r\n";
671 ##********************************************************************
672 ## print_dewey(): gets info from MARC field 082
673 ## Arguments: field (082)
674 ##********************************************************************
675 sub print_dewey {
676 my($deweyfield) = @_;
678 if (!$deweyfield || length ($deweyfield->subfield('a')) == 0) {
679 print "<marc>no Dewey number found (082\$a)\r\n" if $marcprint;
680 warn("no Dewey number found") if $marcprint;
682 else {
683 print "U1 - ", &charconv($deweyfield->subfield('a')), " ", &charconv($deweyfield->subfield('2')), "\r\n";
687 ##********************************************************************
688 ## print_pubinfo(): gets info from MARC field 260
689 ## Arguments: field (260)
690 ##********************************************************************
691 sub print_pubinfo {
692 my($pubinfofield) = @_;
694 if (!$pubinfofield) {
695 print "<marc>no publication information found (260/264)\r\n" if $marcprint;
696 warn("no publication information found") if $marcprint;
698 else {
699 ## the following information is available in MARC21:
700 ## $a place -> CY
701 ## $b publisher -> PB
702 ## $c date -> PY
703 ## the corresponding subfields for UNIMARC:
704 ## $a place -> CY
705 ## $c publisher -> PB
706 ## $d date -> PY
708 ## all of them are repeatable. We pool all places into a
709 ## comma-separated list in CY. We also pool all publishers
710 ## into a comma-separated list in PB. We break the rule with
711 ## the date field because this wouldn't make much sense. In
712 ## this case, we use the first occurrence for PY, the second
713 ## for Y2, and ignore the rest
715 my @pubsubfields = $pubinfofield->subfields();
716 my @cities;
717 my @publishers;
718 my $pycounter = 0;
720 my $pubsub_place;
721 my $pubsub_publisher;
722 my $pubsub_date;
724 if ($intype eq "unimarc") {
725 $pubsub_place = "a";
726 $pubsub_publisher = "c";
727 $pubsub_date = "d";
729 else { ## assume marc21
730 $pubsub_place = "a";
731 $pubsub_publisher = "b";
732 $pubsub_date = "c";
735 ## loop over all subfield list entries
736 for my $tuple (@pubsubfields) {
737 ## each tuple consists of the subfield code and the value
738 if (@$tuple[0] eq $pubsub_place) {
739 ## strip any trailing crap
740 $_ = @$tuple[1];
741 s% *[,;:/]$%%;
742 ## pool all occurrences in a list
743 push (@cities, $_);
745 elsif (@$tuple[0] eq $pubsub_publisher) {
746 ## strip any trailing crap
747 $_ = @$tuple[1];
748 s% *[,;:/]$%%;
749 ## pool all occurrences in a list
750 push (@publishers, $_);
752 elsif (@$tuple[0] eq $pubsub_date) {
753 ## the dates are free-form, so we want to extract
754 ## a four-digit year and leave the rest as
755 ## "other info"
756 $protoyear = @$tuple[1];
757 print "<marc>Year (260\$c): $protoyear\r\n" if $marcprint;
759 ## strip any separator chars at the end
760 $protoyear =~ s% *[\.;:/]*$%%;
762 ## isolate a four-digit year. We discard anything
763 ## preceding the year, but keep everything after
764 ## the year as other info.
765 $protoyear =~ s%\D*([0-9\-]{4})(.*)%$1///$2%;
767 ## check what we've got. If there is no four-digit
768 ## year, make it up. If digits are replaced by '-',
769 ## replace those with 0s
771 if (index($protoyear, "/") == 4) {
772 ## have year info
773 ## replace all '-' in the four-digit year
774 ## by '0'
775 substr($protoyear,0,4) =~ s!-!0!g;
777 else {
778 ## have no year info
779 print "<marc>no four-digit year found, use 0000\r\n" if $marcprint;
780 $protoyear = "0000///$protoyear";
781 warn("no four-digit year found, use 0000") if $marcprint;
784 if ($pycounter == 0 && length($protoyear)) {
785 print "PY - $protoyear\r\n";
787 elsif ($pycounter == 1 && length($_)) {
788 print "Y2 - $protoyear\r\n";
790 ## else: discard
792 ## else: discard
795 ## now dump the collected CY and PB lists
796 if (@cities > 0) {
797 print "CY - ", &charconv(join(", ", @cities)), "\r\n";
799 if (@publishers > 0) {
800 print "PB - ", &charconv(join(", ", @publishers)), "\r\n";
805 ##********************************************************************
806 ## get_keywords(): prints info from MARC fields 6XX
807 ## Arguments: list of fields (6XX)
808 ##********************************************************************
809 sub get_keywords {
810 my($fieldname, @keywords) = @_;
812 my @kw;
813 ## a list of all possible subfields
814 my @subfields = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'x', 'y', 'z', '2', '3', '4');
816 ## loop over all 6XX fields
817 foreach my $kwfield (@keywords) {
818 if ($kwfield != undef) {
819 ## authornames get special treatment
820 if ($fieldname eq "600") {
821 my $val = normalize_author($kwfield->subfield('a'), $kwfield->subfield('b'), $kwfield->subfield('c'), $kwfield->indicator('1'));
822 push @kw, $val;
823 print "<marc>Field $kwfield subfield a:", $kwfield->subfield('a'), "\r\n<marc>Field $kwfield subfield b:", $kwfield->subfield('b'), "\r\n<marc>Field $kwfield subfield c:", $kwfield->subfield('c'), "\r\n" if $marcprint;
825 else {
826 ## retrieve all available subfields
827 my @kwsubfields = $kwfield->subfields();
829 ## loop over all available subfield tuples
830 foreach my $kwtuple (@kwsubfields) {
831 ## loop over all subfields to check
832 foreach my $subfield (@subfields) {
833 ## [0] contains subfield code
834 if (@$kwtuple[0] eq $subfield) {
835 ## [1] contains value, remove trailing separators
836 @$kwtuple[1] =~ s% *[,;.:/]*$%%;
837 if (length(@$kwtuple[1]) > 0) {
838 push @kw, @$kwtuple[1];
839 print "<marc>Field $fieldname subfield $subfield:", @$kwtuple[1], "\r\n" if $marcprint;
841 ## we can leave the subfields loop here
842 last;
849 return @kw;
852 ##********************************************************************
853 ## pool_subx(): adds contents of several subfields to a list
854 ## Arguments: reference to a list
855 ## field name
856 ## list of fields (5XX)
857 ##********************************************************************
858 sub pool_subx {
859 my($aref, $fieldname, @notefields) = @_;
861 ## we use a list that contains the interesting subfields
862 ## for each field
863 # ToDo: this is apparently correct only for marc21
864 my @subfields;
866 if ($fieldname eq "500") {
867 @subfields = ('a');
869 elsif ($fieldname eq "501") {
870 @subfields = ('a');
872 elsif ($fieldname eq "502") {
873 @subfields = ('a');
875 elsif ($fieldname eq "504") {
876 @subfields = ('a', 'b');
878 elsif ($fieldname eq "505") {
879 @subfields = ('a', 'g', 'r', 't', 'u');
881 elsif ($fieldname eq "506") {
882 @subfields = ('a', 'b', 'c', 'd', 'e');
884 elsif ($fieldname eq "507") {
885 @subfields = ('a', 'b');
887 elsif ($fieldname eq "508") {
888 @subfields = ('a');
890 elsif ($fieldname eq "510") {
891 @subfields = ('a', 'b', 'c', 'x', '3');
893 elsif ($fieldname eq "511") {
894 @subfields = ('a');
896 elsif ($fieldname eq "513") {
897 @subfields = ('a', 'b');
899 elsif ($fieldname eq "514") {
900 @subfields = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'u', 'z');
902 elsif ($fieldname eq "515") {
903 @subfields = ('a');
905 elsif ($fieldname eq "516") {
906 @subfields = ('a');
908 elsif ($fieldname eq "518") {
909 @subfields = ('a', '3');
911 elsif ($fieldname eq "521") {
912 @subfields = ('a', 'b', '3');
914 elsif ($fieldname eq "522") {
915 @subfields = ('a');
917 elsif ($fieldname eq "524") {
918 @subfields = ('a', '2', '3');
920 elsif ($fieldname eq "525") {
921 @subfields = ('a');
923 elsif ($fieldname eq "526") {
924 @subfields = ('a', 'b', 'c', 'd', 'i', 'x', 'z', '5');
926 elsif ($fieldname eq "530") {
927 @subfields = ('a', 'b', 'c', 'd', 'u', '3');
929 elsif ($fieldname eq "533") {
930 @subfields = ('a', 'b', 'c', 'd', 'e', 'f', 'm', 'n', '3');
932 elsif ($fieldname eq "534") {
933 @subfields = ('a', 'b', 'c', 'e', 'f', 'k', 'l', 'm', 'n', 'p', 't', 'x', 'z');
935 elsif ($fieldname eq "535") {
936 @subfields = ('a', 'b', 'c', 'd', 'g', '3');
939 ## loop over all notefields
940 foreach my $notefield (@notefields) {
941 if (defined $notefield) {
942 ## retrieve all available subfield tuples
943 my @notesubfields = $notefield->subfields();
945 ## loop over all subfield tuples
946 foreach my $notetuple (@notesubfields) {
947 ## loop over all subfields to check
948 foreach my $subfield (@subfields) {
949 ## [0] contains subfield code
950 if (@$notetuple[0] eq $subfield) {
951 ## [1] contains value, remove trailing separators
952 print "<marc>field $fieldname subfield $subfield: ", @$notetuple[1], "\r\n" if $marcprint;
953 @$notetuple[1] =~ s% *[,;.:/]*$%%;
954 if (length(@$notetuple[1]) > 0) {
955 ## add to list
956 push @{$aref}, @$notetuple[1];
958 last;
966 ##********************************************************************
967 ## print_abstract(): prints abstract fields
968 ## Arguments: list of fields (520)
969 ##********************************************************************
970 sub print_abstract {
971 # ToDo: take care of repeatable subfields
972 my(@abfields) = @_;
974 ## we check the following subfields
975 my @subfields = ('a', 'b');
977 ## we generate a list for all useful strings
978 my @abstrings;
980 ## loop over all abfields
981 foreach my $abfield (@abfields) {
982 foreach my $field (@subfields) {
983 if ( length( $abfield->subfield($field) ) > 0 ) {
984 my $ab = $abfield->subfield($field);
986 print "<marc>field 520 subfield $field: $ab\r\n" if $marcprint;
988 ## strip trailing separators
989 $ab =~ s% *[;,:./]*$%%;
991 ## add string to the list
992 push( @abstrings, $ab );
997 my $allabs = join "; ", @abstrings;
999 if (length($allabs) > 0) {
1000 print "N2 - ", &charconv($allabs), "\r\n";
1007 ##********************************************************************
1008 ## charconv(): converts to a different charset based on a global var
1009 ## Arguments: string
1010 ## Returns: string
1011 ##********************************************************************
1012 sub charconv {
1013 if ($utf) {
1014 ## return unaltered if already utf-8
1015 return @_;
1017 elsif (my $uniout eq "t") {
1018 ## convert to utf-8
1019 return marc8_to_utf8("@_");
1021 else {
1022 ## return unaltered if no utf-8 requested
1023 return @_;