Sunday, December 23, 2012

Parse Excel (*.xls & *.xlsx) File via PERL

Salam,

Lama tak post disini. selepas pemergian abah hujung bulan jun haritu. saya x ada idea nak tulis apa.

Baru hari ni ada kekuatan untuk menulis semula.

Harini saya nak kongsi mcmana nak parse excel fail yg mengunakan format MS Excel 2003(*.xls) dan kebawah serta format MS Excel 2007(*.xlsx).

Saya mengunakan PERL + Spreadsheet module dari CPAN.

Module Spreadsheet yg saya gunakan,

  • Spreadsheet::ParseExcel
  • Spreadsheet::XLSX

dua module di atas saya pilih sebab byk mengunakan function name yg hampir serupa cuma cara awal fail excel dibaca sahaja ada perbezaan dimana fail berformat *xlsx memerlukan iconv untuk dapat dibaca isi kandungannya.

Berikut contoh keratan

Untuk Fail berformat *.xls

################
sub getxls{
################ 
 
 use Spreadsheet::ParseExcel;
 
 opendir THISFILES, "$dir" or die "cannot open dir '$dir'";
 my @allfiles = readdir THISFILES;
 close THISFILES;
 foreach my $file(@allfiles){
  if($file =~ /\.xls$/i && $file !~ /^\~/i){
   
   my $parser   = Spreadsheet::ParseExcel->new();
   my $workbook = $parser->parse("$dir/$file");
   
   if ( !defined $workbook ) {
       #die $parser->error(), ".\n";
       print $parser->error() . "\n";
   }else{
    for my $worksheet ( $workbook->worksheets() ) {
     my ( $row_min, $row_max ) = $worksheet->row_range();
     my ( $col_min, $col_max ) = $worksheet->col_range();
     my $sheetname = $worksheet->get_name();
     print "$sheetname\n";
     
     for my $row ($row_min .. $row_max ) {
      for my $col ($col_min .. $col_max ) {
       my $cells = $worksheet->get_cell( $row, $col);
       my $cell='';
       if($cells){
        $cell = $cells->unformatted(); #unformated
        #$cell = $cells->value(); #clean
        print "$cell\t";
       }
      }
      print "\n";
     }
    }
   }
  }
 }
}

Untuk Fail berformat *.xlsx

################
sub getxlsx{
################
 
 use Spreadsheet::XLSX;
 use Text::Iconv;
 
 opendir THISFILES, "$dir" or die "cannot open dir '$dir'";
 my @allfiles = readdir THISFILES;
 close THISFILES;
 foreach my $file(@allfiles){
  if($file =~ /\.xlsx$/i && $file !~ /^\~/i){
   
   my $converter = Text::Iconv -> new ("utf-8", "windows-1251");
   my $workbook = Spreadsheet::XLSX->new("$dir/$file", $converter);
   
   if ( !defined $workbook ) {
       #die $parser->error(), ".\n";
       print $parser->error() . "\n";
   }else{
    for my $worksheet ( @{$workbook -> {Worksheet}} ) {
     my ( $row_min, $row_max ) = $worksheet->row_range();
     my ( $col_min, $col_max ) = $worksheet->col_range();
     my $sheetname = $worksheet->get_name();
     print "$sheetname\n";
     
     for my $row ($row_min .. $row_max ) {
      for my $col ($col_min .. $col_max ) {
       my $cells = $worksheet->get_cell( $row, $col);
       my $cell='';
       if($cells){
        $cell = $cells->unformatted(); #unformated
        #$cell = $cells->value(); #clean
        print "$cell\t";
       }
      }
      print "\n";
     }
    }
   }
  }
 }
}

if($file =~ /\.xlsx$/i && $file !~ /^\~/i){

Saya tapis untuk hanya fail *.xlsx sahaja diprosess. dan nama fail bermula dgn '~' juga di keluarkan dari senarai. PERL boleh membaca fail yang dhidden tetapi module ini akan menghasilkan ERROR apabila cuba memperosess fail sebegini. fail yg mengandungi '~' dipermulaan merupakan fail yg telah ditandakan untuk dibuang oleh OS ataupun sebagai fail backup. fail ini tidak boleh dilihat melalui fail browser.

happy coding....