]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/extras/import/marc2bre.pl
removing dup stripping .... it is a unicorn problem
[Evergreen.git] / Open-ILS / src / extras / import / marc2bre.pl
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
4
5 use lib '/openils/lib/perl5/';
6
7 use OpenSRF::System;
8 use OpenSRF::Application;
9 use OpenSRF::EX qw/:try/;
10 use OpenSRF::AppSession;
11 use OpenSRF::MultiSession;
12 use OpenSRF::Utils::SettingsClient;
13 use OpenILS::Application::AppUtils;
14 use OpenILS::Utils::Fieldmapper;
15 use Digest::MD5 qw/md5_hex/;
16 use JSON;
17 use Data::Dumper;
18 use Unicode::Normalize;
19
20 use Time::HiRes qw/time/;
21 use Getopt::Long;
22 use MARC::Batch;
23 use MARC::File::XML;
24 use MARC::Charset;
25 use UNIVERSAL::require;
26
27 MARC::Charset->ignore_errors(1);
28
29 my ($utf8, $id_field, $count, $user, $password, $config, $keyfile,  @files, @trash_fields) =
30         (0, '998', 1, 'admin', 'open-ils', '/openils/conf/bootstrap.conf');
31
32 GetOptions(
33         'startid=i'     => \$count,
34         'idfield=s'     => \$id_field,
35         'user=s'        => \$user,
36         'password=s'    => \$password,
37         'keyfile=s'     => \$keyfile,
38         'config=s'      => \$config,
39         'file=s'        => \@files,
40         'trash=s'       => \@trash_fields,
41 );
42
43 @files = @ARGV if (!@files);
44
45 my @ses;
46 my @req;
47 my %processing_cache;
48
49 my %source_map = (      
50         o  => 'OCLC',
51         i  => 'ISxN',    
52         l  => 'LCCN',
53         s  => 'System',  
54         g  => 'Gutenberg',  
55 );                              
56
57
58 OpenSRF::System->bootstrap_client( config_file => $config );
59 Fieldmapper->import(IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
60
61 #$user = OpenILS::Application::AppUtils->check_user_session( login($user,$password) )->id;
62
63 my %keymap;
64 if ($keyfile) {
65         open F, $keyfile or die "Couldn't open key file $keyfile";
66         while (<F>) {
67                 if ( /^(\d+)\|(\S+)/o ) {
68                         $keymap{$1} = $2;
69                 }
70         }
71 }
72
73 select STDERR; $| = 1;
74 select STDOUT; $| = 1;
75
76 my $batch = new MARC::Batch ( 'USMARC', @files );
77 $batch->strict_off();
78 $batch->warnings_off();
79
80 my $starttime = time;
81 my $rec;
82 while ( try { $rec = $batch->next } otherwise { $rec = -1 } ) {
83         next if ($rec == -1);
84         my $id;
85
86         if ($id_field) {
87                 my $field = $rec->field($id_field);
88                 if ($field) {
89                         if ($field->is_control_field) {
90                                 $id = $field->data;
91                         } else {
92                                 $id = $field->subfield('a');
93                         }
94                 }
95         }
96                 
97         if ($id && $id =~ /(\d+)/o) {
98                 $id = $1;
99         } else {
100                 $id = $count;
101         }
102
103         if ($keyfile) {
104                 if (my $tcn = $keymap{$id}) {
105                         $rec->delete_field( $_ ) for ($rec->field($id_field));
106                         $rec->append_fields( MARC::Field->new( $id_field, '', '', 'a', $tcn ) );
107                 } else {
108                         $count++;
109                         next;
110                 }
111         }
112
113         $rec = preprocess($rec);
114         $rec->delete_field( $_ ) for ($rec->field($id_field));
115
116         if (!$rec) {
117                 next;
118         }
119
120         my $tcn_value = $rec->subfield('901' => 'a');
121         my $tcn_source = $rec->subfield('901' => 'b');
122
123         (my $xml = $rec->as_xml_record()) =~ s/\n//sog;
124         $xml =~ s/^<\?xml.+\?\s*>//go;
125         $xml =~ s/>\s+</></go;
126         $xml =~ s/\p{Cc}//go;
127         $xml = entityize($xml);
128
129         my $bib = new Fieldmapper::biblio::record_entry;
130         $bib->id($id);
131         $bib->active('t');
132         $bib->deleted('f');
133         $bib->marc($xml);
134         $bib->creator($user);
135         $bib->create_date('now');
136         $bib->editor($user);
137         $bib->edit_date('now');
138         $bib->tcn_source($tcn_source);
139         $bib->tcn_value($tcn_value);
140         $bib->last_xact_id('IMPORT-'.$starttime);
141
142         print JSON->perl2JSON($bib)."\n";
143
144         $count++;
145
146         if (!($count % 20)) {
147                 print STDERR "\r$count\t". $count / (time - $starttime);
148         }
149 }
150
151 sub preprocess {
152         my $rec = shift;
153
154         my ($id, $source, $value);
155
156         if (!$id) {
157                 my $f = $rec->field($id_field);
158                 $id = $f->subfield('a') if ($f);
159         }
160
161         if (!$id) {
162                 my $f = $rec->field('001');
163                 $id = $f->data if ($f);
164         }
165
166         if (!$id) {
167                 my $f = $rec->field('000');
168                 $id = $f->data if ($f);
169                 $source = 'g'; # only PG seems to use this
170         }
171
172         if (!$id) {
173                 my $f = $rec->field('020');
174                 $id = $f->subfield('a') if ($f);
175                 $source = 'i';
176         }
177
178         if (!$id) {
179                 my $f = $rec->field('022');
180                 $id = $f->subfield('a') if ($f);
181                 $source = 'i';
182         }
183
184         if (!$id) {
185                 my $f = $rec->field('010');
186                 $id = $f->subfield('a') if ($f);
187                 $source = 'l';
188         }
189
190         if (!$id) {
191                 $count++;
192                 warn "\n !!! Record with no TCN : $count\n".$rec->as_formatted;
193                 return undef;
194         }
195
196         $rec->delete_field($_) for ($rec->field($id_field, @trash_fields));
197
198         $id =~ s/\s*$//o;
199         $id =~ s/^\s*//o;
200         $id =~ s/^(\S+).*$/$1/o;
201
202         $id = $source.$id if ($source);
203
204         ($source, $value) = $id =~ /^(.)(.+)$/o;
205         if ($id =~ /^o(\d+)$/o) {
206                 $id = "ocm$1";
207                 $source = 'o';
208         }
209
210         my $tcn = MARC::Field->new(
211                 '901' => ('', ''),
212                 a => $id,
213                 b => do { $source_map{$source} || 'System' },
214         );
215
216         $rec->append_fields($tcn);
217
218         return $rec;
219 }
220
221 sub login {        
222         my( $username, $password, $type ) = @_;
223
224         $type |= "staff"; 
225
226         my $seed = OpenILS::Application::AppUtils->simplereq(
227                 'open-ils.auth',
228                 'open-ils.auth.authenticate.init',
229                 $username
230         );
231
232         die("No auth seed. Couldn't talk to the auth server") unless $seed;
233
234         my $response = OpenILS::Application::AppUtils->simplereq(
235                 'open-ils.auth',
236                 'open-ils.auth.authenticate.complete',
237                 {       username => $username,
238                         password => md5_hex($seed . md5_hex($password)),
239                         type => $type });
240
241         die("No auth response returned on login.") unless $response;
242
243         my $authtime = $response->{payload}->{authtime};
244         my $authtoken = $response->{payload}->{authtoken};
245
246         die("Login failed for user $username!") unless $authtoken;
247
248         return $authtoken;
249 }       
250
251 sub entityize {
252         my $stuff = shift;
253         my $form = shift;
254
255         if ($form and $form eq 'D') {
256                 $stuff = NFD($stuff);
257         } else {
258                 $stuff = NFC($stuff);
259         }
260
261         $stuff =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
262         return $stuff;
263 }
264