Jak to z Microsoftem bywa nie jest łatwo. Są dwa formaty Excela -- stary (.xls
) oraz nowy (.xlsx
). Pakiety Perlowe Spreadsheet::Excel
oraz Spreadsheet::ParseXLSX
radzą sobie nieźle, aczkolwiek oczywiście gwarancji nie ma i być nie może skoro sam Excel czasami siebie samego nie potrafi zinterpretować.
No ale jest jeszcze trzeci format: jak plik .xlsx
jest zabezpieczone hasłem (password protected). I na taką okoliczność nie ma zbyt wielu narzędzi. Można wszakże problem rozwiązać w dwóch krokach korzystając Libreoffice, który potrafi interpretować pliki Excela i można go uruchomić w trybie batch:
#!/bin/bash XLS="$1" TMP="${XLS%.*}.xlsx" libreoffice --headless --convert-to xlsx "$XLS" --outdir ./xlsx-temp/ perl xslx2csv.pl ./xlsx-temp/"$TMP" "$OUTFILE"
Powyższy skrypt obsłuży wszystkie rodzaje plików Excela, zamieniając je najpierw na plik w formacie XLSX (plik password protected zostanie zmieniony na prawdziwy format XLSX, interpretowalny przez np. Spreadsheet::ParseXLSX
).
Można od razu konwertować do CSV (--convert-to csv
), ale konwersji będzie podlegać tylko pierwszy arkusz. Jak interesuje nas na przykład drugi, to kicha... nie da się (a przynajmniej ja nie wiem jak to osiągnąć). Inny problem to zamiana XLSX→XLSX -- nie ma w LibreOffice możliwości określenia nazwy pliku wynikowego, a próba:
libreoffice --headless --convert-to xlsx plik.xlsx
Kończy się błędem. Na szczęście jest obejście w postaci opcji --outdir
. Plik wyjściowy -- o tej samej nazwie co wejściowy -- jest zapisywany w innym katalogu i problem rozwiązany.
Po zamianie Excela na ,,kanoniczny'' XLSX do konwersji na CSV można wykorzystać następujący skrypt Perla:
#!/usr/bin/perl # Wykorzystanie perl xslx2csv.pl plik.xslx [numer-arkusza] use Spreadsheet::ParseXLSX; use open ":encoding(utf8)"; use open IN => ":encoding(utf8)", OUT => ":utf8"; $xslxfile = $ARGV[0]; $ArkuszNo = $ARGV[1] || 1; ## domyślnie arkuszu 1 my $source_excel = new Spreadsheet::ParseXLSX; my $source_book = $source_excel->parse("$xslxfile") or die "Could not open source Excel file $xslxfile: $!"; # Zapisuje zawartość wybranego arkusza do hasza %csv my %csv = (); foreach my $sheet_number (0 .. $source_book->{SheetCount}-1) { my $sheet = $source_book->{Worksheet}[$sheet_number]; print STDERR "*** SHEET:", $sheet->{Name}, "/", $sheet_number, "\n"; if ( $ArkuszNo == $sheet_number + 1 ) { next unless defined $sheet->{MaxRow}; next unless $sheet->{MinRow} <= $sheet->{MaxRow}; next unless defined $sheet->{MaxCol}; next unless $sheet->{MinCol} <= $sheet->{MaxCol}; foreach my $row_index ($sheet->{MinRow} .. $sheet->{MaxRow}) { foreach my $col_index ($sheet->{MinCol} .. $sheet->{MaxCol}) { my $source_cell = $sheet->{Cells}[$row_index][$col_index]; if ($source_cell) { $csv{$row_index}{$col_index} = $source_cell->Value; } } } } }
Arkusz jest w haszu %csv
. Jak go przekształcić/wydrukować itp. pozostawiam inwencji ewentualnego czytelnika.
Warto jest zapoznać się z tak ciekawymi informacjami.
OdpowiedzUsuń