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

Legend:
Removed from v.7  
changed lines
  Added in v.81

  ViewVC Help
Powered by ViewVC 1.1.26