john.tm has asked for the wisdom of the Perl Monks concerning the following question:

I have a script that converts xlsx files to csv files. but how can i just convert a specific(named) worksheet from an xlsx workbook (with multiple worksheets) to a csv file.
#!/usr/bin/perl use strict; use warnings; use Spreadsheet::BasicRead; use Excel::Writer::XLSX; use Spreadsheet::ParseExcel; my $xlsx = ("c:\\acb.xlsx"),,1; my $csv = ("c:\\acb.csv"),,1; if (-e $xlsx) { my $ss2 = new Spreadsheet::BasicRead($xlsx) or die; my $name2 = ''; my $row2 = 0; open(FILE2, ">$csv") or die ; binmode(FILE2, ":utf8"); # Wide character in print warnings while (my $data2 = $ss2->getNextRow()){ $row2++; $name2 = join(',', @$data2); print FILE2 $name2."\n" if ($name2 ne ""); } close FILE2; }
  • Comment on Perl to convert a named workseet from an xlsx workbook with multiple worksheets into a csv file
  • Download Code

Replies are listed 'Best First'.
Re: Perl to convert a named workseet from an xlsx workbook with multiple worksheets into a csv file
by Tux (Canon) on Nov 22, 2014 at 09:36 UTC

    It is VERY error prone to use join "," to write CSV from cell data: what if the cell contains a , (or a newline)? Use a CSV module to generate CSV file, like Text::CSV_XS or Text::CSV.

    If you use Spreadsheet::Read instead of your set of the three modules, you'd be able to pick a sheet by name. FWIW Spreadsheet::BasicRead requires the other two modules, but you do not have to include those requirements in your script).

    For reading xlsx spreadsheets, please use Spreadsheet::ParseXLSX (Spreadsheet::BasicRead (still) uses Spreadsheet::XLSX which is buggy and unmaintained). Any alternative will make you suffer later on. (Spreadsheet::Read uses Spreadsheet::ParseXLSX).

    Here is an example for using the modules (tested):

    use 5.16.2; use warnings; sub usage { die "usage: $0 file.xlsx name [out.csv]\n"; } my $xls = shift or usage; my $sht = shift or usage; my $out = shift // $xls; $out =~ s/\.xlsx$/.csv/i; use Spreadsheet::Read; use Text::CSV_XS; my $csv = Text::CSV_XS->new ({ binary => 1, eol => "\r\n", auto_diag = +> 1 }); open my $fh, ">", $out or die "$out: $!\n"; my $book = ReadData ($xls) or die "$xls: $!\n"; my $sheet = $book->[$book->[0]{sheet}{$sht}]; foreach my $row (1 .. $sheet->{maxrow}) { $csv->print ($fh, [ Spreadsheet::Read::row ($sheet, $row) ]); } close $fh;

    Enjoy, Have FUN! H.Merijn
Re: Perl to convert a named workseet from an xlsx workbook with multiple worksheets into a csv file
by Loops (Curate) on Nov 22, 2014 at 02:12 UTC

    Looks like Spreadsheet::BasicRead doesn't have the ability to select sheet by name. But it does allow you to select each sheet by number, and then query its name... so:

    sub sheetNames { my $xlsx = shift; my %ret; my $sheet = $xlsx->getFirstSheet; while ($sheet) { $ret{$xlsx->currentSheetName} = $xlsx->currentSheetNum; $sheet = $xlsx->getNextSheet; } return %ret; } sub selectSheet { my ($xlsx,$name) = @_; my %available = sheetNames $xlsx; $xlsx->setCurrentSheetNum($available{$name}); }

    And then before your csv export code runs, do:

    selectSheet $ss2, 'My Great Sheet';

    Error checking should be added of course, currently it'll just silently fail if the sheet you choose doesn't actually exist.

Re: Perl to convert a named workseet from an xlsx workbook with multiple worksheets into a csv file
by ww (Archbishop) on Nov 22, 2014 at 02:33 UTC

    Is there a reason to do this without using Excel's native capabilities?


    ++$anecdote ne $data


      It is part of a bigger script that runs each day.

        Fair enough, but that is using the "bigger script" optimal? So far you haven't told us that there's any substantive objection to having the "bigger script" shell out... or pre-selecting a worksheet (worksheets?) to convert before it (they?) provide data in cvs format to the "bigger script.

        One reason the latter might be sub-optimal would be that the "bigger script" is -- in effect -- merely a kind of batch file -- one starting a series of (non-native executables?) actions on a large set of spreadsheets... but even that seems amenable to re-factoring, if Tux' reply (above) doesn't meet your needs.


        ++$anecdote ne $data