| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package App::Tables::Excel; | 
| 2 | 2 | 50 |  | 2 |  | 52 | BEGIN { die "Your perl version is old, see README for instructions" if $] < 5.005; } | 
| 3 |  |  |  |  |  |  |  | 
| 4 | 2 |  |  | 2 |  | 31 | use strict; | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 59 |  | 
| 5 | 2 |  |  | 2 |  | 2705 | use Data::Table; | 
|  | 2 |  |  |  |  | 70009 |  | 
|  | 2 |  |  |  |  | 88 |  | 
| 6 | 2 |  |  | 2 |  | 4328 | use Spreadsheet::WriteExcel; | 
|  | 2 |  |  |  |  | 223389 |  | 
|  | 2 |  |  |  |  | 99 |  | 
| 7 | 2 |  |  | 2 |  | 5279 | use Spreadsheet::ParseExcel; | 
|  | 2 |  |  |  |  | 121352 |  | 
|  | 2 |  |  |  |  | 76 |  | 
| 8 | 2 |  |  | 2 |  | 2135 | use Spreadsheet::XLSX; | 
|  | 2 |  |  |  |  | 173982 |  | 
|  | 2 |  |  |  |  | 63 |  | 
| 9 | 2 |  |  | 2 |  | 4223 | use Excel::Writer::XLSX; | 
|  | 2 |  |  |  |  | 314061 |  | 
|  | 2 |  |  |  |  | 93 |  | 
| 10 | 2 |  |  | 2 |  | 26 | use vars qw(@ISA @EXPORT @EXPORT_OK); | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 138 |  | 
| 11 | 2 |  |  | 2 |  | 11 | use Carp; | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 112 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 2 |  |  | 2 |  | 12 | use Exporter 'import'; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 9238 |  | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | @ISA = qw(Exporter AutoLoader); | 
| 16 |  |  |  |  |  |  | # Items to export into callers namespace by default. Note: do not export | 
| 17 |  |  |  |  |  |  | # names by default without a very good reason. Use EXPORT_OK instead. | 
| 18 |  |  |  |  |  |  | # Do not simply export all your public functions/methods/constants. | 
| 19 |  |  |  |  |  |  | @EXPORT = (); | 
| 20 |  |  |  |  |  |  | @EXPORT_OK = qw( | 
| 21 |  |  |  |  |  |  | tables2xls xls2tables tables2xlsx xlsx2tables | 
| 22 |  |  |  |  |  |  | tables_from_file | 
| 23 |  |  |  |  |  |  | ); | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | sub xls2tables { | 
| 26 | 0 |  |  | 0 | 1 |  | my ($fileName, $sheetNames, $sheetIndices) = @_; | 
| 27 | 0 |  |  |  |  |  | return excelFileToTable($fileName, $sheetNames, $sheetIndices, '2003'); | 
| 28 |  |  |  |  |  |  | } | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | sub xlsx2tables { | 
| 31 | 0 |  |  | 0 | 1 |  | my ($fileName, $sheetNames, $sheetIndices) = @_; | 
| 32 | 0 |  |  |  |  |  | return excelFileToTable($fileName, $sheetNames, $sheetIndices, '2007'); | 
| 33 |  |  |  |  |  |  | } | 
| 34 |  |  |  |  |  |  |  | 
| 35 | 0 |  |  | 0 | 0 |  | sub H_BUILT { 1 } | 
| 36 | 0 |  |  | 0 | 0 |  | sub H_READ  { 2 } | 
| 37 | 0 |  |  | 0 | 0 |  | sub H_GUESS { 3 } | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | sub excelFileToTable { | 
| 40 | 0 |  |  | 0 | 0 |  | my ($fileName, $sheetNames, $sheetIndices, $excelFormat, $headers_are ) = @_; | 
| 41 | 0 |  |  |  |  |  | for my $h ($headers_are) { | 
| 42 | 0 | 0 |  |  |  |  | $h = | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | $h eq 'built'  ? H_BUILT : | 
| 44 |  |  |  |  |  |  | $h eq 'read'   ? H_READ  : | 
| 45 |  |  |  |  |  |  | $h eq 'guess'  ? H_GUESS : | 
| 46 |  |  |  |  |  |  | $h; | 
| 47 | 0 | 0 | 0 |  |  |  | ($h > 0) && ($h < 4) or die; | 
| 48 |  |  |  |  |  |  | } | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 0 |  |  |  |  |  | my %sheetsName = (); | 
| 51 | 0 |  |  |  |  |  | my %sheetsIndex = (); | 
| 52 | 0 | 0 | 0 |  |  |  | if (defined($sheetNames) && ref($sheetNames) eq 'ARRAY') { | 
|  |  | 0 | 0 |  |  |  |  | 
| 53 | 0 |  |  |  |  |  | foreach my $name (@$sheetNames) { | 
| 54 | 0 |  |  |  |  |  | $sheetsName{$name} = 1; | 
| 55 |  |  |  |  |  |  | } | 
| 56 |  |  |  |  |  |  | } elsif (defined($sheetIndices) && ref($sheetIndices) eq 'ARRAY') { | 
| 57 | 0 |  |  |  |  |  | foreach my $idx (@$sheetIndices) { | 
| 58 | 0 |  |  |  |  |  | $sheetsIndex{$idx} = 1; | 
| 59 |  |  |  |  |  |  | } | 
| 60 |  |  |  |  |  |  | } | 
| 61 | 0 |  |  |  |  |  | my $excel = undef; | 
| 62 | 0 | 0 |  |  |  |  | if ($excelFormat eq '2003') { | 
|  |  | 0 |  |  |  |  |  | 
| 63 | 0 |  |  |  |  |  | $excel = Spreadsheet::ParseExcel::Workbook->Parse($fileName); | 
| 64 |  |  |  |  |  |  | } elsif ($excelFormat eq '2007') { | 
| 65 | 0 |  |  |  |  |  | $excel = Spreadsheet::XLSX->new($fileName); | 
| 66 |  |  |  |  |  |  | } else { | 
| 67 | 0 |  |  |  |  |  | croak "Unrecognized Excel format, must be either 2003 or 2007!"; | 
| 68 |  |  |  |  |  |  | } | 
| 69 | 0 |  |  |  |  |  | my @tables = (); | 
| 70 | 0 |  |  |  |  |  | my @sheets = (); | 
| 71 | 0 |  |  |  |  |  | my $num = 0; | 
| 72 | 0 |  |  |  |  |  | foreach my $sheet (@{$excel->{Worksheet}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 73 | 0 |  |  |  |  |  | $num++; | 
| 74 | 0 | 0 | 0 |  |  |  | next if ((scalar keys %sheetsName) && !defined($sheetsName{$sheet->{Name}})); | 
| 75 | 0 | 0 | 0 |  |  |  | next if ((scalar keys %sheetsIndex) && !defined($sheetsIndex{$num})); | 
| 76 | 0 | 0 | 0 |  |  |  | next unless defined($sheet->{MinRow}) && defined($sheet->{MaxRow}) && defined($sheet->{MinCol}) && defined($sheet->{MaxRow}); | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 77 | 0 |  |  |  |  |  | push @sheets, $sheet->{Name}; | 
| 78 |  |  |  |  |  |  | #printf("Sheet: %s\n", $sheet->{Name}); | 
| 79 | 0 |  | 0 |  |  |  | $sheet->{MaxRow} ||= $sheet->{MinRow}; | 
| 80 | 0 |  | 0 |  |  |  | $sheet->{MaxCol} ||= $sheet->{MinCol}; | 
| 81 | 0 |  |  |  |  |  | my @header = (); | 
| 82 | 0 |  |  |  |  |  | foreach my $col ($sheet->{MinCol} ..  $sheet->{MaxCol}) { | 
| 83 | 0 |  |  |  |  |  | my $cel=$sheet->{Cells}[$sheet->{MinRow}][$col]; | 
| 84 | 0 | 0 |  |  |  |  | push @header, defined($cel)?$cel->{Val}:undef; | 
| 85 |  |  |  |  |  |  | } | 
| 86 |  |  |  |  |  |  |  | 
| 87 | 0 |  |  |  |  |  | my $t = do { | 
| 88 | 0 |  |  |  |  |  | my $h = $headers_are; | 
| 89 | 0 | 0 |  |  |  |  | $h == H_GUESS and $h = do { | 
| 90 | 0 |  |  |  |  |  | my $d =  $Data::Table::DEFAULTS{CSV_DELIMITER}; | 
| 91 | 0 |  |  |  |  |  | my $s = join $d, map {Data::Table::csvEscape($_)} @header; | 
|  | 0 |  |  |  |  |  |  | 
| 92 | 0 | 0 |  |  |  |  | (Data::Table::fromFileIsHeader $s, $d) | 
| 93 |  |  |  |  |  |  | ? H_READ : H_BUILT | 
| 94 |  |  |  |  |  |  | }; | 
| 95 | 0 | 0 |  |  |  |  | if    ( $h == H_READ  ) { Data::Table->new( [], \@header, 0) } | 
|  | 0 | 0 |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | elsif ( $h == H_BUILT ) { | 
| 97 | 0 |  |  |  |  |  | Data::Table->new | 
| 98 |  |  |  |  |  |  | ( [\@header] | 
| 99 |  |  |  |  |  |  | , [ map "col$_", 1..($sheet->{MaxCol}-$sheet->{MinCol}+1) ] | 
| 100 |  |  |  |  |  |  | , 0 ); | 
| 101 |  |  |  |  |  |  | } | 
| 102 | 0 |  |  |  |  |  | else { die } | 
| 103 |  |  |  |  |  |  | }; | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 0 |  |  |  |  |  | foreach my $row (($sheet->{MinRow}+1) .. $sheet->{MaxRow}) { | 
| 106 | 0 |  |  |  |  |  | my @one = (); | 
| 107 | 0 |  |  |  |  |  | foreach my $col ($sheet->{MinCol} ..  $sheet->{MaxCol}) { | 
| 108 | 0 |  |  |  |  |  | my $cel=$sheet->{Cells}[$row][$col]; | 
| 109 | 0 | 0 |  |  |  |  | push @one, defined($cel)?$cel->{Val}:undef; | 
| 110 |  |  |  |  |  |  | } | 
| 111 | 0 |  |  |  |  |  | $t->addRow(\@one); | 
| 112 |  |  |  |  |  |  | } | 
| 113 | 0 |  |  |  |  |  | push @tables, $t; | 
| 114 |  |  |  |  |  |  | } | 
| 115 | 0 |  |  |  |  |  | return (\@tables, \@sheets); | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | sub tables_from_file { | 
| 119 | 0 |  |  | 0 | 0 |  | my ( $file, %with ) = @_; | 
| 120 | 0 |  | 0 |  |  |  | $with{headers_are} ||= 'built'; | 
| 121 | 0 |  | 0 |  |  |  | $with{format} ||= do { | 
| 122 | 0 |  |  |  |  |  | $file =~ /[.]((xls)x)$/; | 
| 123 | 0 | 0 |  |  |  |  | $1 ? 2007 : | 
|  |  | 0 |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | $2 ? 2003 : die "can't guess the excel version"; | 
| 125 |  |  |  |  |  |  | }; | 
| 126 | 0 |  | 0 |  |  |  | for (qw( names indices )) { $with{$_} ||= undef } | 
|  | 0 |  |  |  |  |  |  | 
| 127 | 0 |  |  |  |  |  | excelFileToTable $file | 
| 128 |  |  |  |  |  |  | , @with{qw( names indices format headers_are )}; | 
| 129 |  |  |  |  |  |  | } | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | # color palette is defined in | 
| 132 |  |  |  |  |  |  | # http://search.cpan.org/src/JMCNAMARA/Spreadsheet-WriteExcel-2.20/doc/palette.html | 
| 133 |  |  |  |  |  |  | sub oneTable2Worksheet { | 
| 134 | 0 |  |  | 0 | 0 |  | my ($workbook, $t, $name, $colors, $portrait) = @_; | 
| 135 |  |  |  |  |  |  | # Add a worksheet | 
| 136 | 0 |  |  |  |  |  | my $worksheet = $workbook->add_worksheet($name); | 
| 137 | 0 | 0 |  |  |  |  | $portrait=1 unless defined($portrait); | 
| 138 |  |  |  |  |  |  | #my @BG_COLOR=(26,47,44); | 
| 139 | 0 |  |  |  |  |  | my @BG_COLOR=(44, 9, 30); | 
| 140 | 0 | 0 | 0 |  |  |  | @BG_COLOR=@$colors if ((ref($colors) eq "ARRAY") && (scalar @$colors==3)); | 
| 141 | 0 |  |  |  |  |  | my $fmt_header= $workbook->add_format(); | 
| 142 | 0 |  |  |  |  |  | $fmt_header->set_bg_color($BG_COLOR[2]); | 
| 143 | 0 |  |  |  |  |  | $fmt_header->set_bold(); | 
| 144 | 0 |  |  |  |  |  | $fmt_header->set_color('white'); | 
| 145 | 0 |  |  |  |  |  | my $fmt_odd= $workbook->add_format(); | 
| 146 | 0 |  |  |  |  |  | $fmt_odd->set_bg_color($BG_COLOR[0]); | 
| 147 | 0 |  |  |  |  |  | my $fmt_even= $workbook->add_format(); | 
| 148 | 0 |  |  |  |  |  | $fmt_even->set_bg_color($BG_COLOR[1]); | 
| 149 | 0 |  |  |  |  |  | my @FORMAT = ($fmt_odd, $fmt_even); | 
| 150 |  |  |  |  |  |  |  | 
| 151 | 0 |  |  |  |  |  | my @header=$t->header; | 
| 152 | 0 | 0 |  |  |  |  | if ($portrait) { | 
| 153 | 0 |  |  |  |  |  | for (my $i=0; $i<@header; $i++) { | 
| 154 | 0 |  |  |  |  |  | $worksheet->write(0, $i, $header[$i], $fmt_header); | 
| 155 |  |  |  |  |  |  | } | 
| 156 | 0 |  |  |  |  |  | for (my $i=0; $i<$t->nofRow; $i++) { | 
| 157 | 0 |  |  |  |  |  | for (my $j=0; $j<$t->nofCol; $j++) { | 
| 158 | 0 |  |  |  |  |  | $worksheet->write($i+1, $j, $t->elm($i,$j), $FORMAT[$i%2]); | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  | } else { | 
| 162 | 0 |  |  |  |  |  | for (my $i=0; $i<@header; $i++) { | 
| 163 | 0 |  |  |  |  |  | $worksheet->write($i, 0, $header[$i], $fmt_header); | 
| 164 |  |  |  |  |  |  | } | 
| 165 | 0 |  |  |  |  |  | for (my $i=0; $i<$t->nofRow; $i++) { | 
| 166 | 0 |  |  |  |  |  | for (my $j=0; $j<$t->nofCol; $j++) { | 
| 167 | 0 |  |  |  |  |  | $worksheet->write($j, $i+1, $t->elm($i,$j), $FORMAT[$i%2]); | 
| 168 |  |  |  |  |  |  | } | 
| 169 |  |  |  |  |  |  | } | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  | } | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | sub tables2excelFile { | 
| 174 | 0 |  |  | 0 | 0 |  | my ($fileName, $tables, $names, $colors, $portrait, $excelFormat) = @_; | 
| 175 | 0 | 0 | 0 |  |  |  | confess("No table is specified!\n") unless (defined($tables)&&(scalar @$tables)); | 
| 176 | 0 | 0 |  |  |  |  | $names =[] unless defined($names); | 
| 177 | 0 | 0 |  |  |  |  | $colors=[] unless defined($colors); | 
| 178 | 0 | 0 |  |  |  |  | $portrait=[] unless defined($portrait); | 
| 179 | 0 |  |  |  |  |  | my $workbook = undef; | 
| 180 | 0 | 0 |  |  |  |  | if ($excelFormat eq '2003') { | 
|  |  | 0 |  |  |  |  |  | 
| 181 | 0 |  |  |  |  |  | $workbook = Spreadsheet::WriteExcel->new($fileName); | 
| 182 |  |  |  |  |  |  | } elsif ($excelFormat eq '2007') { | 
| 183 | 0 |  |  |  |  |  | $workbook = Excel::Writer::XLSX->new($fileName); | 
| 184 |  |  |  |  |  |  | } else { | 
| 185 | 0 |  |  |  |  |  | croak "Unrecognized Excel format, must be either 2003 or 2007!"; | 
| 186 |  |  |  |  |  |  | } | 
| 187 | 0 | 0 |  |  |  |  | $portrait=[] unless defined($portrait); | 
| 188 | 0 |  |  |  |  |  | my ($prevColors, $prevPortrait) = (undef, undef); | 
| 189 | 0 |  |  |  |  |  | for (my $i=0; $i<@$tables; $i++) { | 
| 190 | 0 |  |  |  |  |  | my $myColor=$colors->[$i]; | 
| 191 | 0 | 0 | 0 |  |  |  | $myColor=$prevColors if (!defined($myColor) && defined($prevColors)); | 
| 192 | 0 |  |  |  |  |  | $prevColors=$myColor; | 
| 193 | 0 |  |  |  |  |  | my $myPortrait=$portrait->[$i]; | 
| 194 | 0 | 0 | 0 |  |  |  | $myPortrait=$prevPortrait if (!defined($myPortrait) && defined($prevPortrait)); | 
| 195 | 0 |  |  |  |  |  | $prevPortrait=$myPortrait; | 
| 196 | 0 | 0 |  |  |  |  | my $mySheet = $names->[$i] ? $names->[$i]:"Sheet".($i+1); | 
| 197 | 0 |  |  |  |  |  | oneTable2Worksheet($workbook, $tables->[$i], $mySheet, $myColor, $myPortrait); | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  | } | 
| 200 |  |  |  |  |  |  |  | 
| 201 |  |  |  |  |  |  | sub tables2xls { | 
| 202 | 0 |  |  | 0 | 1 |  | my ($fileName, $tables, $names, $colors, $portrait) = @_; | 
| 203 | 0 |  |  |  |  |  | tables2excelFile($fileName, $tables, $names, $colors, $portrait, '2003'); | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | sub tables2xlsx { | 
| 207 | 0 |  |  | 0 | 1 |  | my ($fileName, $tables, $names, $colors, $portrait) = @_; | 
| 208 | 0 |  |  |  |  |  | tables2excelFile($fileName, $tables, $names, $colors, $portrait, '2007'); | 
| 209 |  |  |  |  |  |  | } | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | 1; | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | __END__ |