File Coverage

blib/lib/App/Tables/Excel.pm
Criterion Covered Total %
statement 28 145 19.3
branch 1 66 1.5
condition 0 48 0.0
subroutine 10 21 47.6
pod 4 11 36.3
total 43 291 14.7


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__