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