fix tests
[Biblio-Z3950.git] / CROSBI.pm
1 package CROSBI;
2
3 use warnings;
4 use strict;
5
6 use MARC::Record;
7 use Data::Dump qw/dump/;
8 use DBI;
9 use utf8;
10
11 use base 'Scraper';
12
13 my $debug = $ENV{DEBUG} || 0;
14
15 sub diag {
16         warn "# ", @_, $/;
17 }
18
19
20 # Koha Z39.50 query:
21 #
22 # Bib-1 @and @and @and @and @and @and @and @or
23 # @attr 1=4 title 
24 # @attr 1=7 isbn
25 # @attr 1=8 issn 
26 # @attr 1=1003 author 
27 # @attr 1=16 dewey (godina)
28 # @attr 1=21 subject-holding 
29 # @attr 1=12 control-no 
30 # @attr 1=1007 standard-id 
31 # @attr 1=1016 any
32
33 sub usemap {{
34         4               => 'fti_pr:',
35         7               => 'fti_pr:',
36         8               => 'fti_pr:',
37         1003            => 'fti_au:',
38         16              => 'fti_pr:',
39         21              => 'fti_pr:',
40         12              => 'fti_pr:',
41         1007            => 'fti_pr:',
42         1016            => 'fti_au,fti_pr:',
43 }};
44
45 =for sql
46
47 =cut
48
49 my $dbname = 'bibliografija';
50 my @and;
51 my @exec;
52
53 sub search {
54         my ( $self, $query ) = @_;
55
56         utf8::decode( $query );
57         warn "QUERY",dump( $query );
58
59         die "need query" unless defined $query;
60
61         $query =~ s/^\s+//;
62         $query =~ s/\s+$//;
63
64         my $table = lc $self->{database};
65         $table =~ s/^crosbi-//g;
66
67         $self->{_table} = $table;
68
69         my $sql = qq{
70
71 select
72         $table.*
73         ,ARRAY( select napomena from rad_napomena where rad_napomena.id = $table.id ) as rad_napomena
74         ,ARRAY( select projekt from rad_projekt where rad_projekt.id = $table.id ) as rad_projekt
75         ,ARRAY( select datum from rad_godina where rad_godina.id = $table.id ) as rad_godina
76         ,ARRAY( select sifra from rad_podrucje where rad_podrucje.id = $table.id ) as rad_podrucje
77         ,ARRAY( select url from url where url.id = $table.id ) as url
78 from $table
79 inner join rad_ustanova using (id) -- sifra
80         };
81
82         @and = ( qq{ rad_ustanova.sifra = ? } );
83         @exec =  ( 130 ); # FIXME ustanova
84
85                 sub parse_fti {
86                         my $query = shift;
87                         warn "## parse_fti [$query]";
88                         my $fti;
89                         if ( $query =~ s/^(fti_.+):// ) {
90                                 $fti = $1;
91                         } else {
92                                 warn "INVALID QUERY no fti_xxx: [$query]";
93                         }
94
95                         my $tsquery = join(' & ', split(/\s+/,$query) );
96
97                         my @or;
98                         foreach my $f ( split(/,/,$fti) ) {
99                                 push @or, "$f @@ to_tsquery(?)";
100                                 push @exec, $tsquery;
101                         };
102                         push @and, "( " . join(" or ", @or) . ")";
103                 }
104
105         if ( $query =~ / AND / ) {
106                 foreach my $and ( split(/ AND /, $query) ) {
107                         parse_fti $and;
108                 }
109         } elsif ( $query =~ m/fti_.+:/ ) {
110                 parse_fti $query;
111         } else { # no " AND " in query
112                 my $tsquery = join(' & ', split(/\s+/,$query) );
113                 push @and, "( fti_au @@ to_tsquery(?) or fti_pr @@ to_tsquery(?) )";
114                 push @exec, $tsquery,  $tsquery;
115         }
116
117
118         $sql .= "where " . join(" and ", @and);
119
120 warn "XXX SQL = ",$sql, dump( @exec );
121
122         my $dbh = DBI->connect_cached("dbi:Pg:dbname=$dbname", '', '', {AutoCommit => 0});
123
124         my $sth = $dbh->prepare( $sql );
125
126         $sth->execute( @exec );
127
128         my $hits = $sth->rows;
129
130         $self->{_sth} = $sth;
131
132         warn "# [$query] $hits hits\n";
133
134         return $self->{hits} = $hits;
135 }
136
137 my $langrecode008 = {
138         'bugarski' => 'bul',
139         'Češki' => 'cze',
140         'češki' => 'cze',
141         'ENG' => 'eng',
142         'Esperanto' => 'epo',
143         'FRA' => 'fra',
144         'GER' => 'ger',
145         'HRV' => 'hrv',
146         'ITA' => 'ita',
147         'Japanski' => 'jpn',
148         'Latinski' => 'lat',
149         'mađarski' => 'hun',
150         'Madžarski' => 'hun',
151         'Makedonski' => 'mac',
152         'nizozemski' => 'dut',
153         'Poljski' => 'pol',
154         'poljski' => 'pol',
155         'Portugalski' => 'por',
156         'portugalski' => 'por',
157         'RUS' => 'rus',
158         'Rumunjski' => 'rum',
159         'rumunjski' => 'rum',
160         'rusinski' => 'sla',
161         'slovački' => 'slo',
162         'slovenski' => 'slv',
163         'SLV' => 'slv',
164         'SPA' => 'spa',
165         'Srpski' => 'srp',
166         'srpski' => 'srp',
167         'Turski' => 'tur',
168         'turski' => 'tur',
169         'ukrajinski' => 'ukr',
170         'HRV-ENG' => 'mul',
171         'HRV-GER' => 'mul',
172         'hrvatsko-francuski' => 'mul',
173 } ;
174
175 sub next_marc {
176         my ($self,$format) = @_;
177
178         $format ||= 'marc';
179
180         my $sth = $self->{_sth} || die "no _sth";
181         my $row = $sth->fetchrow_hashref;
182
183         warn "## row = ",dump($row) if $ENV{DEBUG};
184
185         warn "ERROR: no row" unless $row;
186
187         my $id = $row->{id} || die "no id";
188
189         my $marc = MARC::Record->new;
190         $marc->encoding('UTF-8');
191
192         my $leader = $marc->leader;
193
194 # /srv/webpac2/conf/crosbi/2016-12-12/casopis-dbi2marc.pl
195
196 ## LDR 05 - n - new
197 ## LDR 06 - a - language material 
198 ## LDR 07 - a - monographic component part 
199
200         $leader =~ s/^(.....)...(.+)/$1naa$2/;
201
202 ## LDR 17 - Encoding level ; 7 - minimal level, u - unknown
203 ## LDR 18 - i = isbd ; u = unknown
204
205         $leader =~ s/^(.{17})..(.+)/$1ui$2/;
206
207         $marc->leader( $leader );
208         warn "# leader [$leader]";
209
210
211 ### 008 - All materials
212
213 ## 008 - 00-05 - Date entered on file 
214
215         my $f008 = $1 . $2 . $3 if $row->{time_date} =~ m/\d\d(\d\d)-(\d\d)-(\d\d)/;
216
217 ## 008 06 - Type of date/Publication status
218
219         $f008 .= 's';
220
221 ## 008 07-10 - Date 1
222
223         $f008 .= substr( $row->{rad_godina}->[0] ,0,4);
224
225 ## 008 11-14 - Date 2 
226
227         #$f008 .= '    ';
228
229         $f008 .= ' ' x ( 15 - length($f008) ); # pad to 15 position
230 ## 008 15-17 - Place of publication, production, or execution - ako nema 102, popunjava se s |
231         $f008 .= 'xx ';
232
233 ## 008 29 - Conference publication
234         $f008 .= ' ' x ( 29 - length($f008) );
235         $f008 .= $self->{_table} eq 'zbornik' ? '1' : '0';
236
237 ## 008 35-37 - Language
238         $f008 .= ' ' x ( 35 - length($f008) ); # pad to 35 position
239         if ( my $lng = $langrecode008->{ $row->{jezik} } ) {
240                 $f008 .= $lng;
241         } else {
242                 warn "INFO unknown jezik [$row->{jezik}] insert into langrecode008!";
243                 #$f008 .= '   ';
244         }
245         $f008 .= ' ' x ( 38 - length($f008) );
246 ## 008 38 - Modified record
247         $f008 .= '|';
248 ## 008 39 - Cataloging source - d (other)
249         $f008 .= 'd';
250
251         warn "# 008 ",length($f008);
252         
253         $marc->add_fields('008', $f008); # FIXME - mglavica check
254
255
256         if ( my $doi = $row->{doi} ) {
257
258                 $marc->add_fields('024','7',' ',
259                         2 => 'doi',
260                         a => $doi,
261                 );
262
263         }
264
265 ### 035$
266
267 ## marc 035a - System Number 
268 ## polje moze  sadrzavati slova i razmake
269 ## moguc problem u pretrazivanju ako ima zagrade, kako bi trebalo po standardu
270
271         $marc->add_fields('035',' ',' ',
272                 a => join('', '(CROSBI)', $row->{id})
273         );
274
275 ### 040
276 ## za sve je isti
277
278         $marc->add_fields('040',' ',' ',
279                 'a' => 'HR-ZaFF',
280                 'b' => 'hrv',
281                 'c' => 'HR-ZaFF',
282                 'e' => 'ppiak'
283         );
284
285 ### 041 - indikatori
286 # i1=0 - Item not a translation/does not include a translation
287 # i1=1 - Item is or includes a translation
288 # i1=' ' - No information provided
289
290 ### 041
291 # ponovljivo potpolje (041a) - marc_repeatable_subfield
292 # koristi se kad ima vise od jednog jezika, ili kad se radi o prijevodu
293
294         $marc->add_fields('041',' ',' ', map {
295                 ( a => lc($_) )
296         } split(/-/, $row->{jezik}));
297
298
299 ### 080
300 ### 245 indikatori
301 ## i1 = 0 zza anonimne publikacije, i1 = 1 ako postoji 700 ili 710
302 ## i2 = pretpostavlja se na temelju clana na pocetku naslova i jezika
303
304         my ( $first_author, $authors ) = split(/ ;\s*/,$row->{autori});
305
306         $marc->add_fields(100,'1',' ','a' => $first_author );
307
308
309
310         my $naslov = $row->{naslov}; # XXX title?
311
312         my $i2 =
313                 $naslov =~ m/^Eine /                            ? 5 :
314                 $naslov =~ m/(Die|Das|Der|Ein|Les|Los|The) /    ? 4 :
315                 $naslov =~ m/^(Um|Un|An|La|Le|Lo|Il) /          ? 3 :
316                 $naslov =~ m/^(A|L) /                           ? 2 :
317                 $naslov =~ m/^L'/                               ? 2 :
318                                                                   0;
319
320         $marc->add_fields(245,'1',$i2,
321                 'a' => $naslov . ' /',
322                 'c' => $row->{autori} . '.',
323         );
324
325         $marc->add_fields(246,'3',' ',
326                 'i' => 'Naslov na engleskom:',
327                 'a' => $row->{title}
328         );
329
330         sub page_range {
331                 my ( $prefix, $from, $to ) = @_;
332                 my $out;
333                 if ( $from ) {
334                         $out = $prefix . $from;
335                         $out .= '-' . $to if $to;
336                 }
337                 return $out;
338         }
339
340         # fake date for Koha import
341         $marc->add_fields(260,' ',' ',
342                 c => $row->{godina},
343         );
344
345         $marc->add_fields(300,' ',' ',
346                 a => page_range('',$row->{stranica_prva},$row->{stranica_zadnja}),
347                 f => 'str.'
348         );
349
350         $marc->add_fields(363,' ',' ',
351                 a => $row->{volumen},
352                 b => $row->{broj},
353                 i => $row->{godina},
354         ) if $row->{volumen};
355
356 # /data/FF/crosbi/2016-12-12/casopis-rad_napomena.sql
357
358         foreach my $napomena ( @{ $row->{rad_napomena} } ) {
359                 $marc->add_fields(500,' ',' ',
360                         a => substr($napomena, 0, 9999), # XXX marc limit for one subfield is 4 digits in dictionary
361                 );
362         }
363
364         $marc->add_fields(520,' ',' ',
365                 a => substr($row->{sazetak}, 0, 9999)
366         );
367
368
369         if ( $row->{rad_projekt} ) {
370                 $marc->add_fields(536,' ',' ',
371                         a => 'Projekt MZOS',
372                         f => 'projekt',
373                 );
374         }
375
376         $marc->add_fields(546,' ',' ',
377                 a => $row->{jezik}
378         );
379
380         foreach my $v ( @{ $row->{rad_podrucje} } ) {
381                 $marc->add_fields(690,' ',' ',
382                         a => $v,
383                 );
384         }
385
386
387         $marc->add_fields(693,' ',' ',
388                 a => $row->{kljucne_rijeci},
389                 1 => 'hrv',
390                 2 => 'crosbi',
391         );
392         $marc->add_fields(693,' ',' ',
393                 a => $row->{key_words},
394                 1 => 'eng',
395                 2 => 'crosbi',
396         );
397
398         if ( $row->{autori} =~ m/ ; / ) {
399                 my @a = split(/ ; /, $row->{autori});
400                 shift @a; # skip first
401                 $marc->add_fields(700,'1',' ',
402                         a => $_,
403                         4 => 'aut'
404                 ) foreach @a;
405         }
406
407
408         if ( $row->{casopis} ) {
409
410         $marc->add_fields(773,'0',' ',
411                 t => $row->{casopis},
412                 x => $row->{issn},
413                 g => "$row->{volumen} ($row->{godina}), $row->{broj} ;" . page_range(' str. ',$row->{stranica_prva}, $row->{stranica_zadnja}),
414         );
415
416         } elsif ( $row->{knjiga} ) {
417
418         # rknjiga-dbi2marc.pl
419         $marc->add_fields(773,'0',' ',
420                 t => $row->{knjiga},
421                 d => "$row->{grad} : $row->{nakladnik}, $row->{godina}",
422                 k => $row->{serija},
423                 h => $row->{ukupno_stranica},
424                 n => $row->{uredink},
425                 z => $row->{isbn},
426                 g => page_range(' str. ',$row->{stranica_prva}, $row->{stranica_zadnja}),
427         );
428
429         } elsif ( $row->{zbornik} ) {
430
431         # zbornik-dbi2marc.pl
432         $marc->add_fields(773,'0',' ',
433                 t => $row->{skup},
434                 d => "$row->{grad} : $row->{nakladnik}, $row->{godina}",
435                 k => $row->{serija},
436                 h => $row->{ukupno_stranica},
437                 n => $row->{uredink},
438                 z => $row->{isbn},
439                 g => page_range(' str. ',$row->{stranica_prva}, $row->{stranica_zadnja}),
440         );
441
442         } else {
443                 die "ERROR: 773 undefined in row ",dump($row);
444         }
445
446
447         if ( my $file = $row->{datoteka} ) {
448                 $marc->add_fields(856,' ',' ',
449                         u => "http://bib.irb.hr/datoteka/$file",
450                 );
451         };
452
453
454         $marc->add_fields(856,' ',' ',
455                 u => $row->{openurl},
456         ) if $row->{openurl};
457
458         foreach my $url ( @{ $row->{url} } ) {
459                 $marc->add_fields(856,' ',' ',
460                         u => $url,
461                 );
462         }
463
464         my $f942c = {
465                 casopis  => 'CLA',
466                 preprint => 'PRE',
467                 rknjiga  => 'POG',
468                 zbornik  => 'RZB',
469         };
470
471         my @f942 = (
472                 c => $f942c->{ $self->{_table} } || die "no table $self->{_table} in ".dump($f942c),
473         );
474
475         if ( $row->{status_rada} ) {
476                 push @f942, (
477                 f => 1,
478                 g => $row->{status_rada}
479                 );
480         }
481
482         if ( $self->{_table} =~ m/(casopis|preprint)/ ) {
483
484                 if ( $row->{kategorija} =~ m/Znanstveni/ ) {
485                         push @f942, t => '1.01'
486                 } elsif ( $row->{kategorija} =~ m/Strucni/ ) {
487                         push @f942, t => '1.04';
488                 } else {
489                         warn "ERROR kategorija $row->{kategorija}";
490                 }
491
492         } elsif ( $self->{_table} =~ m/rknjiga/ ) {
493
494                 if ( $row->{kategorija} =~ m/Znanstveni/ ) {
495                         push @f942, t => '1.16.1';
496                 } elsif ( $row->{kategorija} =~ m/Pregledni/ ) {
497                         push @f942, t => '1.16.2';
498                 } elsif ( $row->{kategorija} =~ m/Strucni/ ) {
499                         push @f942, t => '1.17';
500                 } else {
501                         warn "ERROR kategorija $row->{kategorija}";
502                 }
503
504         } elsif ( $self->{_table} =~ m/zbornik/ ) {
505
506                 push @f942, v => $row->{vrst_recenzije};
507
508         } else {
509                 die "ERROR _table $self->{_table}";
510         }
511
512         $marc->add_fields(942,' ',' ',
513                 @f942,
514                 u => '1',
515                 z => join(' - ', grep { defined $_ } ($row->{kategorija}, $row->{vrst_sudjelovanja}, $row->{vrsta_rada})),
516         );
517
518 =for later
519         $marc->add_fields(999,' ',' ',
520                 a => $row->{}
521         );
522
523 =cut
524
525 #       diag "# hash ",dump($hash);
526         diag "# marc\n", $marc->as_formatted if $ENV{DEBUG};
527
528         $self->save_marc( "$id.marc", $marc->as_usmarc );
529
530         return $id;
531
532 }
533
534 1;