/[webpac]/trunk/all2xml.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/all2xml.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3 by dpavlin, Sat Nov 30 00:36:34 2002 UTC revision 90 by dpavlin, Sun Jul 13 13:22:50 2003 UTC
# Line 5  use OpenIsis; Line 5  use OpenIsis;
5  use Getopt::Std;  use Getopt::Std;
6  use Data::Dumper;  use Data::Dumper;
7  use XML::Simple;  use XML::Simple;
8  use Text::Unaccent;  use Text::Unaccent 1.02;        # 1.01 won't compile on my platform,
9  require Unicode::Map8;  use Text::Iconv;
10    use Config::IniFiles;
11  my $config=XMLin(undef, forcearray => [ 'isis' ], forcecontent => 1);  use Encode;
12    
13    $|=1;
14    
15    my $config_file = $0;
16    $config_file =~ s/\.pl$/.conf/;
17    die "FATAL: can't find configuration file '$config_file'" if (! -e $config_file);
18    
19    my $config;
20    
21    #use index_DBI;         # default DBI module for index
22    use index_DBI_cache;    # faster DBI module using memory cache
23    my $index;
24    
25  my %opts;  my %opts;
26    
27  getopts('d:m:q', \%opts);  # usage:
28    #       -d directory name
29    #       -m multiple directories
30    #       -q quiet
31    #       -s run swish
32    
33    getopts('d:m:qs', \%opts);
34    
35    my $path;       # this is name of database
36    
37    Text::Iconv->raise_error(0);     # Conversion errors don't raise exceptions
38    
39    # this is encoding of all files on disk, including import_xml/*.xml file and
40    # filter/*.pm files! It will be used to store strings in perl internally!
41    my $codepage = 'ISO-8859-2';
42    
43    my $utf2cp = Text::Iconv->new('UTF-8',$codepage);
44    # this function will convert data from XML files to local encoding
45    sub x {
46            return $utf2cp->convert($_[0]);
47    }
48    
49  my $db_dir = $opts{d} || "ps";  # FIX  # decode isis/excel or other import codepage
50    my $import2cp;
51    
52  #die "usage: $0 -d [database_dir] -m [database1,database2] " if (! %opts);  # outgoing xml must be in UTF-8
53    my $cp2utf = Text::Iconv->new($codepage,'UTF-8');
54    
55  #print Dumper($config->{indexer});  # mapping between data type and tag which specify
56  #print "-" x 70,"\n";  # format in XML file
57    my %type2tag = (
58            'isis' => 'isis',
59            'excel' => 'column',
60            'marc' => 'marc',
61            'feed' => 'feed'
62    );
63    
64  # how to convert isis code page to UTF8?  sub data2xml {
 my $isis_map = Unicode::Map8->new($config->{isis_codepage}) || die;  
65    
66  sub isis2xml {          use xmlify;
67    
68            my $type = shift @_;
69          my $row = shift @_;          my $row = shift @_;
70            my $add_xml = shift @_;
71            # needed to read values from configuration file
72            my $cfg = shift @_;
73            my $database = shift @_;
74    
75          my $xml;          my $xml;
76    
77          sub isis_sf {          use parse_format;
78                  my $row = shift @_;  
79                  my $isis_id = shift @_;          my $html = "";          # html formatted display output
80                  my $subfield = shift @_;  
81                  if ($row->{$isis_id}->[0]) {          my %field_usage;        # counter for usage of each field
82                          my $sf = OpenIsis::subfields($row->{$isis_id}->[0]);  
83                          if (! defined $subfield || length($subfield) == 0) {          # sort subrouting using order="" attribute
84                                  # subfield list undef, empty or no defined subfields for this record          sub by_order {
85                                  return $row->{$isis_id}->[0];                  return 0 if (! $config->{indexer}->{$a}->{order});
86                          } elsif ($sf->{$subfield}) {                  return 0 if (! $config->{indexer}->{$b}->{order});
87                                  return $sf->{$subfield};  
88                          }                  return $config->{indexer}->{$a}->{order} <=>
89                  }                          $config->{indexer}->{$b}->{order} ;
90          }          }
91    
92          foreach my $field (keys %{$config->{indexer}}) {          foreach my $field (sort by_order keys %{$config->{indexer}}) {
93    
94                    $field=x($field);
95    
96                    $field_usage{$field}++;
97    
98                    my $swish_data = "";
99                  my $display_data = "";                  my $display_data = "";
100                  my $index_data = "";                  my $line_delimiter;
101    
102                  foreach my $x (@{$config->{indexer}->{$field}->{isis}}) {                  my ($swish,$display);
103    
104                          my $display_tmp = "";                  my $tag = $type2tag{$type} || die "can't find which tag to use for type $type";
105                          my $index_tmp = "";                  foreach my $x (@{$config->{indexer}->{$field}->{$tag}}) {
106    
107                          my $format = $x->{content};                          my $format = x($x->{content});
108                          my $i = 1;      # index only                          my $delimiter = x($x->{delimiter}) || ' ';
109                          my $d = 1;      # display only  
110                          $i = 0 if (lc($x->{type}) eq "display");                          my $repeat_off = 0;             # repeatable offset
111                          $d = 0 if (lc($x->{type}) eq "index");  
112  #print "## i: $i d: $d ## $format ##";                            my ($s,$d,$i) = (1,1,0);        # swish, display default
113                          # parse format                          $s = 0 if (lc($x->{type}) eq "display");
114                          my $prefix = "";                          $d = 0 if (lc($x->{type}) eq "swish");
115                          if ($format =~ s/^([^\d]+)//) {                          ($s,$d,$i) = (0,0,1) if (lc($x->{type}) eq "index");
116                                  $prefix = $1;  
117                          }                          # what will separate last line from this one?
118                          while ($format) {                          if ($display_data && $x->{append} && $x->{append} eq "1") {
119                                  if ($format =~ s/^(\d\d\d)(\w?)//) {                                  $line_delimiter = ' ';
120                                          my $isis_tmp = isis_sf($row,$1,$2);                          } elsif ($display_data) {
121                                          if ($isis_tmp) {                                  $line_delimiter = '<br/>';
122  #                                               $display_tmp .= $prefix . "/$1/$2/".$isis_tmp if ($d);                          }
123                                                  $display_tmp .= $prefix . $isis_tmp if ($d);  
124                                                  $index_tmp .= $isis_tmp." " if ($i);                          # init vars so that we go into while...
125  #print " $isis_tmp <--\n";                          ($swish,$display) = (1,1);
126                                          }  
127                                          $prefix = "";                          # while because of repeatable fields
128                                  } elsif ($format =~ s/^([^\d]+)//) {                          while ($swish || $display) {
129                                          $prefix = $1;                                  ($swish,$display) = parse_format($type, $format,$row,$repeat_off++,$import2cp);
130                                  } else {                                  if ($repeat_off > 1000) {
131                                          print STDERR "WARNING: unparsed format '$format'\n";                                          print STDERR "loop (more than 1000 repeatable fields) deteced in $row, $format\n";
132                                          last;                                          last;
133                                  };                                  }
134                                    
135                                    # filter="name" ; filter this field through
136                                    # filter/[name].pm
137                                    my $filter = $x->{filter};
138                                    if ($filter) {
139                                            require "filter/".$filter.".pm";
140                                    }
141                                    # type="swish" ; field for swish
142                                    if ($s && $swish) {
143                                            if ($filter) {
144                                                    no strict 'refs';
145                                                    $swish_data .= join(" ",&$filter($swish));
146                                            } else {
147                                                    $swish_data .= $swish;
148                                            }
149                                    }
150    
151                                    # type="display" ; field for display
152                                    if ($d && $display) {
153                                            if ($line_delimiter && $display_data) {
154                                                    $display_data .= $line_delimiter;
155                                                    undef $line_delimiter;
156                                            }
157                                            if ($filter) {
158                                                    no strict 'refs';
159                                                    $display_data .= join($delimiter,&$filter($display));
160                                            } else {
161                                                    if ($display_data) {
162                                                            $display_data .= $delimiter.$display;
163                                                    } else {
164                                                            $display_data .= $display;
165                                                    }
166                                            }
167                                    }
168                                                    
169                                    # type="index" ; insert into index
170                                    if ($i && $display) {
171                                            my $index_data = $display;
172                                            if ($filter) {
173                                                    no strict 'refs';
174                                                    foreach my $d (&$filter($index_data)) {
175                                                            $index->insert($field, $d, $path);
176                                                    }
177                                            } else {
178                                                    $index->insert($field, $index_data, $path);
179                                            }
180                                    }
181                          }                          }
182                          # add suffix                  }
183                          $display_tmp .= $prefix if ($display_tmp);  
184                    # now try to parse variables from configuration file
185                    foreach my $x (@{$config->{indexer}->{$field}->{'config'}}) {
186    
187                            my $delimiter = x($x->{delimiter}) || ' ';
188                            my $val = $cfg->val($database, x($x->{content}));
189    
190  #                       $display_data .= $display_tmp if ($display_tmp ne "");                          my ($s,$d,$i) = (1,1,0);        # swish, display default
191  #                       $index_data .= $index_tmp if ($index_tmp ne "");                          $s = 0 if (lc($x->{type}) eq "display");
192                          $display_data .= $display_tmp;                          $d = 0 if (lc($x->{type}) eq "swish");
193                          $index_data .= $index_tmp;                          ($s,$d,$i) = (0,0,1) if (lc($x->{type}) eq "index");
194    
195                            if ($val) {
196                                    $display_data .= $delimiter.$val if ($d);
197                                    $swish_data .= $val if ($s);
198                                    $index->insert($field, $val, $path) if ($i);
199                            }
200    
201                  }                  }
202  #print "--display:$display_data\n--index:$index_data\n";  
203                  $xml->{$field}->{display} .= $isis_map->tou($display_data)->utf8 if ($display_data);  
204                  $xml->{$field}->{index} .= unac_string($config->{isis_codepage},$index_data) if ($index_data);                  if ($display_data) {
205            
206                            if ($field eq "headline") {
207                                    $xml .= xmlify("headline", $display_data);
208                            } else {
209    
210                                    # find field name (signular, plural)
211                                    my $field_name = "";
212                                    if ($config->{indexer}->{$field}->{name_singular} && $field_usage{$field} == 1) {
213                                            $field_name = $config->{indexer}->{$field}->{name_singular}."#-#";
214                                    } elsif ($config->{indexer}->{$field}->{name_plural}) {
215                                            $field_name = $config->{indexer}->{$field}->{name_plural}."#-#";
216                                    } elsif ($config->{indexer}->{$field}->{name}) {
217                                            $field_name = $config->{indexer}->{$field}->{name}."#-#";
218                                    } else {
219                                            print STDERR "WARNING: field '$field' doesn't have 'name' attribute!";
220                                    }
221                                    if ($field_name) {
222                                            $html .= x($field_name);
223                                    }
224                                    $html .= $display_data."###\n";
225                            }
226                    }
227                    if ($swish_data) {
228                            # remove extra spaces
229                            $swish_data =~ s/ +/ /g;
230                            $swish_data =~ s/ +$//g;
231    
232                            $xml .= xmlify($field."_swish", unac_string($codepage,$swish_data));
233                    }
234    
235    
236          }          }
237    
238            # dump formatted output in <html>
239            if ($html) {
240                    #$xml .= xmlify("html",$html);
241                    $xml .= "<html><![CDATA[ $html ]]></html>";
242            }
243            
244          if ($xml) {          if ($xml) {
245                  return XMLout($xml, rootname => 'xml', noattr => 1 );                  $xml .= $add_xml if ($add_xml);
246                    return "<xml>\n$xml</xml>\n";
247          } else {          } else {
248                  return;                  return;
249          }          }
# Line 106  sub isis2xml { Line 251  sub isis2xml {
251    
252  ##########################################################################  ##########################################################################
253    
254  my $last_tell=0;  # read configuration for this script
255    my $cfg = new Config::IniFiles( -file => $config_file );
256    
257  my @isis_dirs = ( '.' );        # use dirname as database name  # read global.conf configuration
258    my $cfg_global = new Config::IniFiles( -file => 'global.conf' );
259    
260  if ($opts{m}) {  # open index
261          @isis_dirs = split(/,/,$opts{m});  $index = new index_DBI(
262  }                  $cfg_global->val('global', 'dbi_dbd'),
263                    $cfg_global->val('global', 'dbi_dsn'),
264                    $cfg_global->val('global', 'dbi_user'),
265                    $cfg_global->val('global', 'dbi_passwd') || '',
266            );
267    
268  my @isis_dbs;  foreach my $database ($cfg->Sections) {
269    
270  foreach (@isis_dirs) {          my $type = lc($cfg -> val($database, 'type')) || die "$database doesn't have 'type' defined";
271          if (-e $config->{isis_data}."/$db_dir/$_/LIBRI") {          my $add_xml = $cfg -> val($database, 'xml');    # optional
272                  push @isis_dbs,$config->{isis_data}."/$db_dir/$_/LIBRI/LIBRI";  
273          }  print STDERR "reading ./import_xml/$type.xml\n";
274          if (-e $config->{isis_data}."/$db_dir/$_/PERI") {  
275                  push @isis_dbs,$config->{isis_data}."/$db_dir/$_/PERI/PERI";          # extract just type basic
276          }          my $type_base = $type;
277          if (-e $config->{isis_data}."/$db_dir/$_/AMS") {          $type_base =~ s/_.+$//g;
278                  push @isis_dbs,$config->{isis_data}."/$db_dir/$_/AMS/AMS";  
279            $config=XMLin("./import_xml/$type.xml", forcearray => [ $type2tag{$type_base}, 'config' ], forcecontent => 1);
280    
281            # output current progress indicator
282            my $last_p = 0;
283            sub progress {
284                    #return if (! $opts{q});        # FIXME
285                    my $current = shift;
286                    my $total = shift || 1;
287                    my $p = int($current * 100 / $total);
288                    if ($p != $last_p) {
289                            printf STDERR ("%5d / %5d [%-51s] %-2d %% \r",$current,$total,"=" x ($p/2).">", $p );
290                            $last_p = $p;
291                    }
292          }          }
293          if (-e $config->{isis_data}."/$db_dir/$_/ARTI") {  
294  #               push @isis_dbs,$config->{isis_data}."/$db_dir/$_/ARTI/ARTI";          my $fake_dir = 1;
295            sub fakeprogress {
296                    my $current = shift @_;
297    
298                    my @ind = ('-','\\','|','/','-','\\','|','/', '-');
299    
300                    $last_p += $fake_dir;
301                    $fake_dir = -$fake_dir if ($last_p > 1000 || $last_p < 0);
302                    if ($last_p % 10 == 0) {
303                            printf STDERR ("%5d / %5s [%-51s]\r",$current,"?"," " x ($last_p/20).$ind[($last_p/20) % $#ind]);
304                    }
305          }          }
 }  
306    
307  print STDERR "FATAL: Can't find isis database.\nPerhaps isis_data (".$config->{isis_data}.") has wrong value?\n" if (! @isis_dbs);          # now read database
308    print STDERR "using: $type...\n";
309    
310  my $db;          if ($type_base eq "isis") {
311    
312  foreach my $isis_db (@isis_dbs) {                  my $isis_db = $cfg -> val($database, 'isis_db') || die "$database doesn't have 'isis_db' defined!";
313    
314                    $import2cp = Text::Iconv->new($config->{isis_codepage},$codepage);
315                    my $db = OpenIsis::open( $isis_db );
316    
317          my $db = OpenIsis::open( $isis_db );                  my $max_rowid = OpenIsis::maxRowid( $db );
         if (0) {  
 #       # FIX  
 #       if (! $db ) {  
                 print STDERR "WARNING: can't open '$isis_db'\n";  
                 next ;  
         }  
318    
319          my $max_rowid = OpenIsis::maxRowid( $db );                  print STDERR "Reading database: $isis_db [$max_rowid rows]\n";
320    
321          print STDERR "Reading database: $isis_db [$max_rowid rows]\n";                  my $path = $database;
322    
323          my $last_p = 0;                  for (my $row_id = 1; $row_id <= $max_rowid; $row_id++ ) {
324                            my $row = OpenIsis::read( $db, $row_id );
325                            if ($row && $row->{mfn}) {
326            
327                                    progress($row->{mfn}, $max_rowid);
328    
329                                    my $swishpath = $path."#".int($row->{mfn});
330    
331  #       { my $row_id = 1;                                  if (my $xml = data2xml($type_base,$row,$add_xml,$cfg,$database)) {
332  # FIX                                          $xml = $cp2utf->convert($xml);
333          for (my $row_id = 1; $row_id <= $max_rowid; $row_id++ ) {                                          use bytes;      # as opposed to chars
334                  my $row = OpenIsis::read( $db, $row_id );                                          print "Path-Name: $swishpath\n";
335                  if ($row && $row->{mfn}) {                                          print "Content-Length: ".(length($xml)+1)."\n";
336                                            print "Document-Type: XML\n\n$xml\n";
337                          # output current process indicator                                  }
                         my $p = int($row->{mfn} * 100 / $max_rowid);  
                         if ($p != $last_p) {  
                                 printf STDERR ("%5d / %5d [%-51s] %-2d %% \r",$row->{mfn},$max_rowid,"=" x ($p/2).">", $p ) if (! $opts{q});  
                                 $last_p = $p;  
338                          }                          }
339                    }
340                    print STDERR "\n";
341    
342                          if (my $xml = isis2xml($row)) {          } elsif ($type_base eq "excel") {
343                                  print "Path-Name: $isis_db#".$row->{mfn}."\n";                  use Spreadsheet::ParseExcel;
344                    use Spreadsheet::ParseExcel::Utility qw(int2col);
345                    
346                    $import2cp = Text::Iconv->new($config->{excel_codepage},$codepage);
347                    my $excel_file = $cfg -> val($database, 'excel_file') || die "$database doesn't have 'excel_file' defined!";
348    
349                    my $sheet = x($config->{sheet}) || die "no sheet in $type.xml";
350                    my $start_row = x($config->{start_row}) - 1 || die "no start_row in $type.xml";
351    
352                    my $oBook = Spreadsheet::ParseExcel::Workbook->Parse($excel_file) || die "can't open Excel file '$excel_file'";
353    
354                    my $sheet_nr = 0;
355                    foreach my $oWks (@{$oBook->{Worksheet}}) {
356                            #print STDERR "-- SHEET $sheet_nr:", $oWks->{Name}, "\n";
357                            last if ($oWks->{Name} eq $sheet);
358                            $sheet_nr++;
359                    }
360    
361                    my $oWorksheet = $oBook->{Worksheet}[$sheet_nr];
362            
363                    print STDERR "using sheet: ",$oWorksheet->{Name},"\n";
364                    defined ($oWorksheet) || die "can't find sheet '$sheet' in $excel_file";
365                    my $end_row = x($config->{end_row}) || $oWorksheet->{MaxRow};
366    
367                    for(my $iR = $start_row ; defined $end_row && $iR <= $end_row ; $iR++) {
368                            my $row;
369                            for(my $iC = $oWorksheet->{MinCol} ; defined $oWorksheet->{MaxCol} && $iC <= $oWorksheet->{MaxCol} ; $iC++) {
370                                    my $cell = $oWorksheet->{Cells}[$iR][$iC];
371                                    if ($cell) {
372                                            $row->{int2col($iC)} = $cell->Value;
373                                    }
374                            }
375    
376                            progress($iR, $end_row);
377    
378    #                       print "row[$iR/$end_row] ";
379    #                       foreach (keys %{$row}) {
380    #                               print "$_: ",$row->{$_},"\t";
381    #                       }
382    #                       print "\n";
383    
384                            my $swishpath = $database."#".$iR;
385    
386                            next if (! $row);
387    
388                            if (my $xml = data2xml($type_base,$row,$add_xml,$cfg,$database)) {
389                                    $xml = $cp2utf->convert($xml);
390                                    use bytes;      # as opposed to chars
391                                    print "Path-Name: $swishpath\n";
392                                  print "Content-Length: ".(length($xml)+1)."\n";                                  print "Content-Length: ".(length($xml)+1)."\n";
393                                  print "Document-Type: XML\n\n$xml\n";                                  print "Document-Type: XML\n\n$xml\n";
394                          }                          }
395                  }                  }
396            } elsif ($type_base eq "marc") {
397    
398                    use MARC;
399                    
400                    $import2cp = Text::Iconv->new($config->{marc_codepage},$codepage);
401                    my $marc_file = $cfg -> val($database, 'marc_file') || die "$database doesn't have 'marc_file' defined!";
402    
403                    # optional argument is format
404                    my $format = x($config->{format}) || 'usmarc';
405    
406                    print STDERR "Reading MARC file '$marc_file'\n";
407    
408                    my $marc = new MARC;
409                    my $nr = $marc->openmarc({
410                                    file=>$marc_file, format=>$format
411                            }) || die "Can't open MARC file '$marc_file'";
412    
413                    my $i=0;        # record nr.
414    
415                    my $rec;
416    
417                    while ($marc->nextmarc(1)) {
418    
419                            # XXX
420                            fakeprogress($i++);
421    
422                            my $swishpath = $database."#".$i;
423    
424                            if (my $xml = data2xml($type_base,$marc,$add_xml,$cfg,$database)) {
425                                    $xml = $cp2utf->convert($xml);
426                                    use bytes;      # as opposed to chars
427                                    print "Path-Name: $swishpath\n";
428                                    print "Content-Length: ".(length($xml)+1)."\n";
429                                    print "Document-Type: XML\n\n$xml\n";
430                            }
431                    }
432            } elsif ($type_base eq "feed") {
433    
434                    $import2cp = Text::Iconv->new($config->{feed_codepage},$codepage);
435                    my $prog = x($config->{prog}) || die "$database doesn't have 'prog' defined!";
436    
437                    print STDERR "Reading feed from program '$prog'\n";
438    
439                    open(FEED,"feeds/$prog |") || die "can't start $prog: $!";
440    
441                    my $i=1;        # record nr.
442    
443                    my $data;
444                    my $line=1;
445    
446                    while (<FEED>) {
447                            chomp;
448    
449                            if (/^$/) {
450                                    my $swishpath = $database."#".$i++;
451    
452                                    if (my $xml = data2xml($type_base,$data,$add_xml,$cfg,$database)) {
453                                            $xml = $cp2utf->convert($xml);
454                                            use bytes;      # as opposed to chars
455                                            print "Path-Name: $swishpath\n";
456                                            print "Content-Length: ".(length($xml)+1)."\n";
457                                            print "Document-Type: XML\n\n$xml\n";
458                                    }
459                                    $line = 1;
460                                    $data = {};
461                                    next;
462                            }
463    
464                            $line = $1 if (s/^(\d+):\s*//);
465                            $data->{$line++} = $_;
466    
467                            fakeprogress($i);
468    
469                    }
470          }          }
         print STDERR "\n";  
471  }  }
472    
473    # call this to commit index
474    $index->close;
475    
476  1;  1;
477  __END__  __END__
# Line 182  __END__ Line 479  __END__
479    
480  =head1 NAME  =head1 NAME
481    
482  isis2xml.pl - read isis file and dump XML  all2xml.pl - read various file formats and dump XML for SWISH-E
483    
484  =head1 DESCRIPTION  =head1 DESCRIPTION
485    
486  This command will read ISIS data file using OpenIsis perl module and  This command will read ISIS data file using OpenIsis perl module, MARC
487  create XML file for usage with I<SWISH-E>  records using MARC module and optionally Micro$oft Excel files to
488  indexer. Dispite it's name, this script B<isn't general xml generator>  create one XML file for usage with I<SWISH-E> indexer. Dispite it's name,
489  from isis files (isis allready has something like that). Output of this  this script B<isn't general xml generator> from isis files (isis allready
490  script is tailor-made for SWISH-E.  has something like that). Output of this script is tailor-made for SWISH-E.
491    
492    =head1 BUGS
493    
494    Documentation is really lacking. However, in true Open Source spirit, source
495    is best documentation. I even made considerable effort to comment parts
496    which are not intuitively clear, so...
497    
498  =head1 AUTHOR  =head1 AUTHOR
499    

Legend:
Removed from v.3  
changed lines
  Added in v.90

  ViewVC Help
Powered by ViewVC 1.1.26