line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Excel::Table; |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# Excel::Table.pm - spreadsheet table processing class. |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
=head1 NAME |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
Excel::Table |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 AUTHOR |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Copyright (C) 2012 Tom McMeekin Etmcmeeki@cpan.orgE |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 SYNOPSIS |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
use Excel::Table; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my $xs = Excel::Table->new('dir' => '/cygdrive/c/Users/self/Desktop'); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
for ($xs->list_workbooks) { |
20
|
|
|
|
|
|
|
print "workbook [$_]\n"; |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
$xs->open('mybook.xls'); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
my $wb1 = $xs->open_re('foo*bar*'); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
for my $worksheet ($wb1->worksheets) { |
28
|
|
|
|
|
|
|
print "worksheet: " . $worksheet->get_name() . "\n"; |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
$xs->null("this is a null value"); |
32
|
|
|
|
|
|
|
$xs->force_null(1); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
$xs->rowid(0); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
$xs->trim(0); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my @data = $xs->extract('Sheet1'); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
for (@data) { |
41
|
|
|
|
|
|
|
printf "rowid [%s] title [%s] max_width [%d] value [%s]\n", |
42
|
|
|
|
|
|
|
$_->[0], |
43
|
|
|
|
|
|
|
$xs->titles->[0], |
44
|
|
|
|
|
|
|
$xs->widths->[0], |
45
|
|
|
|
|
|
|
$data{$_}->[0]; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
@data = $xs->extract_hash('Sheet1'); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
@data = $xs->select("column1,column2,column3", 'Sheet1'); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
@data = $xs->select_hash("column1,column2,column3", 'Sheet1'); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
printf "columns %d rows %d title_row %d\n", |
55
|
|
|
|
|
|
|
$xs->columns, $xs->rows, $xs->title_row; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
printf "regexp [%s] pathname [%s] sheet_name [%s]\n", |
58
|
|
|
|
|
|
|
$xs->regexp, $xs->pathname, $xs->sheet_name; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
printf "colid2title(0) = [%s]\n", $xs->colid2title(0); |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
printf "title2colid('Foo') = %d\n", $xs->title2colid('Foo'); |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=head1 DESCRIPTION |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
Excel::Table.pm - spreadsheet table processing. Retrieves worksheets as |
67
|
|
|
|
|
|
|
if they are structured tables array-format. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=over 4 |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=item 1a. OBJ->dir(EXPR) |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Override the directory location in which to look for workbooks. |
74
|
|
|
|
|
|
|
Defaults to "." (i.e. the current working directory). |
75
|
|
|
|
|
|
|
This location is critical to the B, B, |
76
|
|
|
|
|
|
|
and B methods. |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=item 1b. OBJ->list_workbooks |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
Returns an array of workbook files in the directory defined by the |
81
|
|
|
|
|
|
|
B property. |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=item 2a. OBJ->open(EXPR) |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Parses the filename specified by EXPR. The B property |
86
|
|
|
|
|
|
|
will designate the search path. |
87
|
|
|
|
|
|
|
Once opened, via this method (or B) the |
88
|
|
|
|
|
|
|
workbook is available for use by the B method. |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=item 2b. OBJ->open_re(EXPR) |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
This will search for a file which has a filename matching the regexp EXPR. |
93
|
|
|
|
|
|
|
A warning will be issued if multiple matches are found, only the first will |
94
|
|
|
|
|
|
|
be opened. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=item 3. OBJ->regexp |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
Returns the regexp used to search for the workbook on the filesystem. |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=item 4. OBJ->pathname |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
Returns the pathname of the opened workbook. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=item 5a. OBJ->extract(EXPR,[TITLE_ROW]) |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
This will extract all data from the worksheet named EXPR. Data is extracted |
107
|
|
|
|
|
|
|
into an array and returned. Format of data is per below: |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
[ value1, value2, value3, ... ], |
110
|
|
|
|
|
|
|
[ value1, value2, value3, ... ], |
111
|
|
|
|
|
|
|
[ value1, value2, value3, ... ], |
112
|
|
|
|
|
|
|
... |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
The object OBJ will be populated with various properties to assist you to |
115
|
|
|
|
|
|
|
access the data in the array, including column titles and widths. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
A worksheet object is temporarily created in order to populate the array. |
118
|
|
|
|
|
|
|
Once a worksheet is extracted, the associated worksheet object is destroyed. |
119
|
|
|
|
|
|
|
This routine can be called again on any worksheet in the workbook. |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
If the TITLE_ROW argument is specified, then the B property will |
122
|
|
|
|
|
|
|
also be updated prior to extraction. |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=item 5b. OBJ->extract_hash(EXPR,[TITLE_ROW]) |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
Per the B method, but returns an array of hashes, with the hash |
127
|
|
|
|
|
|
|
keys corresponding to the titles. |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=item 5c. OBJ->select(CLAUSE,EXPR,[TITLE_ROW]) |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Similar to the B method, this will extract all rows from the worksheet EXPR, constraining the columns to those specified by the B argument, |
132
|
|
|
|
|
|
|
which is a comma-separated string, e.g. "column1,column2,column3". |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
As with the B method, the B and B properties will |
135
|
|
|
|
|
|
|
be revised. |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=item 5d. OBJ->select_hash(CLAUSE,EXPR,[TITLE_ROW]) |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Per the B |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=item 6. OBJ->columns or OBJ->rows |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
Returns the number of columns or rows available in the sheet extracted via the |
144
|
|
|
|
|
|
|
B method. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=item 7a. OBJ->force_null |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
Flag which determines if whitespace fields should be |
149
|
|
|
|
|
|
|
replaced by specific text (see OBJ->null). |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=item 7b. OBJ->null |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
String to replace whitespace fields with. Defaults to "(null)". |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=item 8. OBJ->rowid |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Flag which determines whether a pseudo-column "rowid" is included in each |
158
|
|
|
|
|
|
|
tuple. The value will take the form "999999999" Defaults to FALSE. |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=item 9. OBJ->sheet_name |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Returns the sheet_name against which data was extracted via B. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=item 10. OBJ->trim |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Flag which determines if trailing whitespace fields should be trimmed. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=item 11a. OBJ->title_row |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
Returns the title row of the worksheet (defaults to zero), following extract. |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=item 11b. OBJ->titles |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Returns an array of title fields, the title row number having been defined |
175
|
|
|
|
|
|
|
as OBJ->title_row. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=item 11c. OBJ->colid2title(colid) |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
Converts the column number (colid) to a string column title (i.e. |
180
|
|
|
|
|
|
|
the offset within the title_row array). |
181
|
|
|
|
|
|
|
If no match, then returns undef. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=item 11d. OBJ->title2colid(REGEXP) |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
Returns the column number of the title identified by REGEXP. |
186
|
|
|
|
|
|
|
If no match, then returns undef. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=item 12. OBJ->widths |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
Returns an array of maximum lengths of any (non-title) data in each column. |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=back |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=cut |
195
|
|
|
|
|
|
|
|
196
|
9
|
|
|
9
|
|
698301
|
use strict; |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
385
|
|
197
|
9
|
|
|
9
|
|
44
|
use warnings; |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
275
|
|
198
|
|
|
|
|
|
|
|
199
|
9
|
|
|
9
|
|
901
|
use Data::Dumper; |
|
9
|
|
|
|
|
11672
|
|
|
9
|
|
|
|
|
653
|
|
200
|
9
|
|
|
9
|
|
8372
|
use Spreadsheet::ParseExcel 0.57; |
|
9
|
|
|
|
|
540692
|
|
|
9
|
|
|
|
|
313
|
|
201
|
9
|
|
|
9
|
|
4992
|
use Spreadsheet::XLSX; |
|
9
|
|
|
|
|
565063
|
|
|
9
|
|
|
|
|
325
|
|
202
|
9
|
|
|
9
|
|
92
|
use File::Basename; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
669
|
|
203
|
|
|
|
|
|
|
|
204
|
9
|
|
|
9
|
|
51
|
use Carp qw(cluck confess); # only use stack backtrace within class |
|
9
|
|
|
|
|
12
|
|
|
9
|
|
|
|
|
510
|
|
205
|
9
|
|
|
9
|
|
47
|
use Log::Log4perl qw/ get_logger /; |
|
9
|
|
|
|
|
11
|
|
|
9
|
|
|
|
|
91
|
|
206
|
|
|
|
|
|
|
|
207
|
9
|
|
|
9
|
|
542
|
use vars qw/ @EXPORT $VERSION /; |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
578
|
|
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
$VERSION = "1.021"; # update this on new release |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
#@ISA = qw(Exporter); |
212
|
|
|
|
|
|
|
#@EXPORT = qw(); |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# package constants |
215
|
9
|
|
|
9
|
|
122
|
use constant S_RID => "rowid"; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
564
|
|
216
|
9
|
|
|
9
|
|
41
|
use constant S_NULL => "(null)"; |
|
9
|
|
|
|
|
10
|
|
|
9
|
|
|
|
|
421
|
|
217
|
9
|
|
|
|
|
518
|
use constant EXT_EXCEL => qw/ |
218
|
|
|
|
|
|
|
\.xls \.xla \.xlb \.xlc \.xld \.xlk \.xll \.xlm \.xlt |
219
|
|
|
|
|
|
|
\.xlv \.xlw \.xls \.xlt |
220
|
9
|
|
|
9
|
|
39
|
/; # known extensions for EXCEL file |
|
9
|
|
|
|
|
11
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# need the Spreadsheet::XLSX module for the following: |
223
|
9
|
|
|
|
|
23338
|
use constant EXT_EXCEL_2007 => qw/ |
224
|
|
|
|
|
|
|
\.xlsx \.xlsm \.xlsb \.xltm \.xlam |
225
|
9
|
|
|
9
|
|
43
|
/; # known extensions for EXCEL 2007 file |
|
9
|
|
|
|
|
11
|
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# package globals |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
our $AUTOLOAD; |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# package locals |
234
|
|
|
|
|
|
|
my $n_Objects = 0; # counter of objects created. |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
my %attribute = ( |
237
|
|
|
|
|
|
|
_n_objects => \$n_Objects, |
238
|
|
|
|
|
|
|
_xl_vers => undef, |
239
|
|
|
|
|
|
|
columns => undef, |
240
|
|
|
|
|
|
|
dir => ".", |
241
|
|
|
|
|
|
|
_log => get_logger("Excel::Table"), |
242
|
|
|
|
|
|
|
null => S_NULL, |
243
|
|
|
|
|
|
|
pathname => undef, |
244
|
|
|
|
|
|
|
regexp => undef, |
245
|
|
|
|
|
|
|
force_null => 0, |
246
|
|
|
|
|
|
|
rows => undef, |
247
|
|
|
|
|
|
|
rowid => 0, |
248
|
|
|
|
|
|
|
sheet_name => undef, |
249
|
|
|
|
|
|
|
title_row => 0, # if title row is zero, first data row is 1 |
250
|
|
|
|
|
|
|
titles => undef, |
251
|
|
|
|
|
|
|
trim => 0, |
252
|
|
|
|
|
|
|
widths => undef, |
253
|
|
|
|
|
|
|
workbook => undef, |
254
|
|
|
|
|
|
|
); |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
#INIT { }; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub AUTOLOAD { |
261
|
18985
|
|
|
18985
|
|
577870
|
my $self = shift; |
262
|
18985
|
50
|
|
|
|
29607
|
my $type = ref($self) or croak("self is not an object"); |
263
|
|
|
|
|
|
|
|
264
|
18985
|
|
|
|
|
16937
|
my $name = $AUTOLOAD; |
265
|
18985
|
|
|
|
|
42574
|
$name =~ s/.*://; # strip fully−qualified portion |
266
|
|
|
|
|
|
|
|
267
|
18985
|
50
|
|
|
|
35565
|
unless (exists $self->{_permitted}->{$name} ) { |
268
|
0
|
|
|
|
|
0
|
confess "no attribute [$name] in class [$type]"; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
18985
|
100
|
|
|
|
23411
|
if (@_) { |
272
|
328
|
|
|
|
|
848
|
return $self->{$name} = shift; |
273
|
|
|
|
|
|
|
} else { |
274
|
18657
|
|
|
|
|
52818
|
return $self->{$name}; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
sub new { |
280
|
24
|
|
|
24
|
0
|
33013
|
my ($class) = shift; |
281
|
|
|
|
|
|
|
#my $self = $class->SUPER::new(@_); |
282
|
24
|
|
|
|
|
346
|
my $self = { _permitted => \%attribute, %attribute }; |
283
|
|
|
|
|
|
|
|
284
|
24
|
|
|
|
|
81
|
++ ${ $self->{_n_objects} }; |
|
24
|
|
|
|
|
62
|
|
285
|
|
|
|
|
|
|
|
286
|
24
|
|
|
|
|
57
|
bless ($self, $class); |
287
|
|
|
|
|
|
|
|
288
|
24
|
|
|
|
|
63
|
my %args = @_; # start processing any parameters passed |
289
|
24
|
|
|
|
|
36
|
my ($method,$value); # start processing any parameters passed |
290
|
24
|
|
|
|
|
137
|
while (($method, $value) = each %args) { |
291
|
|
|
|
|
|
|
|
292
|
31
|
50
|
|
|
|
75
|
confess "SYNTAX new(method => value, ...) value not specified" |
293
|
|
|
|
|
|
|
unless (defined $value); |
294
|
|
|
|
|
|
|
|
295
|
31
|
|
|
|
|
145
|
$self->_log->debug("method [self->$method($value)]"); |
296
|
|
|
|
|
|
|
|
297
|
31
|
|
|
|
|
269
|
$self->$method($value); |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
24
|
|
|
|
|
74
|
return $self; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
sub _determine_xl_vers { |
305
|
290
|
|
|
290
|
|
402
|
my ($self,$pn)=@_; |
306
|
290
|
50
|
|
|
|
512
|
$self->_log->logcroak("SYNTAX: _determine_xl_vers(path)") |
307
|
|
|
|
|
|
|
unless defined ($pn); |
308
|
|
|
|
|
|
|
# return version string or undef for given pathname |
309
|
290
|
|
|
|
|
264
|
my $extension; |
310
|
|
|
|
|
|
|
my @extensions; |
311
|
290
|
|
|
|
|
253
|
my $retval = undef; |
312
|
|
|
|
|
|
|
|
313
|
290
|
|
|
|
|
881
|
$self->_log->debug("pn [$pn]"); |
314
|
|
|
|
|
|
|
|
315
|
290
|
|
|
|
|
2328
|
@extensions = EXT_EXCEL; |
316
|
290
|
|
|
|
|
26154
|
(undef,undef,$extension) = fileparse($pn,@extensions); |
317
|
|
|
|
|
|
|
#$self->_log->debug(sprintf " extension [%s] \@extensions [%s]", $extension, Dumper(\@extensions)); |
318
|
|
|
|
|
|
|
|
319
|
290
|
100
|
|
|
|
774
|
$retval = 'xl2003' if ($extension ne ""); |
320
|
|
|
|
|
|
|
|
321
|
290
|
|
|
|
|
810
|
@extensions = EXT_EXCEL_2007; |
322
|
290
|
|
|
|
|
12506
|
(undef,undef,$extension) = fileparse($pn,@extensions); |
323
|
|
|
|
|
|
|
|
324
|
290
|
100
|
|
|
|
755
|
$retval = 'xl2007' if ($extension ne ""); |
325
|
|
|
|
|
|
|
|
326
|
290
|
100
|
|
|
|
484
|
if (defined $retval) { |
327
|
56
|
|
|
|
|
240
|
$self->_log->debug("pn [$pn] returning [$retval]"); |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
290
|
|
|
|
|
1676
|
return $retval; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sub list_workbooks { |
335
|
13
|
|
|
13
|
1
|
1065
|
my $self = shift; |
336
|
|
|
|
|
|
|
|
337
|
13
|
|
|
|
|
57
|
my $dn = $self->dir; |
338
|
13
|
|
|
|
|
17
|
my ($dh,$fn); |
339
|
0
|
|
|
|
|
0
|
my @workbooks; |
340
|
|
|
|
|
|
|
|
341
|
13
|
|
|
|
|
45
|
$self->_log->debug("dn [$dn]"); |
342
|
|
|
|
|
|
|
|
343
|
13
|
50
|
|
|
|
699
|
opendir($dh, $dn) || $self->_log->logcroak("opendir($dn)"); |
344
|
|
|
|
|
|
|
|
345
|
13
|
|
|
|
|
209
|
while ($fn = readdir($dh)) { |
346
|
260
|
|
|
|
|
2042
|
my $pn = File::Spec->catfile($dn, $fn); |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# need to remember just the filename here, not the path because |
349
|
|
|
|
|
|
|
# open will use the self->dir property to make the path |
350
|
260
|
100
|
|
|
|
596
|
push @workbooks, $fn |
351
|
|
|
|
|
|
|
if (defined($self->_determine_xl_vers($pn))); |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
13
|
|
|
|
|
132
|
closedir $dh; |
355
|
|
|
|
|
|
|
|
356
|
13
|
|
|
|
|
73
|
$self->_log->debug(sprintf '@workbooks [%s]', Dumper(\@workbooks)); |
357
|
|
|
|
|
|
|
|
358
|
13
|
|
|
|
|
1267
|
return @workbooks; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
sub open { |
363
|
30
|
|
|
30
|
1
|
9525
|
my ($self,$fn)=@_; |
364
|
30
|
50
|
|
|
|
108
|
$self->_log->logcroak("SYNTAX: open(file)") unless defined ($fn); |
365
|
30
|
|
|
|
|
196
|
my $pn = File::Spec->catfile($self->dir, $fn); |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
# to look for the file in the cwd, is not good behaviour, |
368
|
|
|
|
|
|
|
# so dir must be explicit, thus the default to "." |
369
|
|
|
|
|
|
|
|
370
|
30
|
50
|
|
|
|
604
|
if (-f $pn) { |
371
|
30
|
|
|
|
|
158
|
$self->pathname($pn); |
372
|
|
|
|
|
|
|
} else { |
373
|
0
|
|
|
|
|
0
|
$self->_log->logcroak("no such path [$pn]"); |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
30
|
|
|
|
|
141
|
$self->_log->debug("parsing [$pn]"); |
377
|
|
|
|
|
|
|
|
378
|
30
|
|
|
|
|
318
|
$self->{'_xl_vers'} = $self->_determine_xl_vers($pn); |
379
|
|
|
|
|
|
|
|
380
|
30
|
|
|
|
|
47
|
my $parser; |
381
|
|
|
|
|
|
|
|
382
|
30
|
100
|
|
|
|
157
|
if ($self->_xl_vers eq 'xl2007') { |
383
|
13
|
|
|
|
|
185
|
$parser = Spreadsheet::XLSX->new($pn); |
384
|
|
|
|
|
|
|
|
385
|
13
|
50
|
|
|
|
409905
|
$self->_log->logcroak("Spreadsheet::XLSX->new($pn) failed") |
386
|
|
|
|
|
|
|
unless defined $parser; |
387
|
|
|
|
|
|
|
|
388
|
13
|
|
|
|
|
127
|
$self->workbook($parser); |
389
|
|
|
|
|
|
|
} else { |
390
|
17
|
|
|
|
|
150
|
$parser = Spreadsheet::ParseExcel->new(); |
391
|
17
|
|
|
|
|
28926
|
$self->workbook($parser->Parse($pn)); |
392
|
|
|
|
|
|
|
|
393
|
17
|
50
|
|
|
|
835
|
$self->_log->logcroak("Parse() failed, error: " . $self->workbook->error()) |
394
|
|
|
|
|
|
|
unless defined $self->workbook; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
|
398
|
30
|
|
|
|
|
146
|
return $self->workbook; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
sub open_re { |
403
|
7
|
|
|
7
|
1
|
3583
|
my $self = shift; |
404
|
7
|
50
|
|
|
|
20
|
if (@_) { $self->regexp(shift); } else { $self->_log->logcroak("SYNTAX: open_re(regexp)"); } |
|
7
|
|
|
|
|
39
|
|
|
0
|
|
|
|
|
0
|
|
405
|
7
|
|
|
|
|
45
|
my $re = $self->regexp; |
406
|
7
|
|
|
|
|
12
|
my $matches = 0; |
407
|
7
|
|
|
|
|
8
|
my $wb = undef; |
408
|
|
|
|
|
|
|
|
409
|
7
|
|
|
|
|
24
|
$self->_log->debug(sprintf "regexp [%s]", $self->regexp); |
410
|
7
|
|
|
|
|
60
|
for ( $self->list_workbooks ) { |
411
|
14
|
|
|
|
|
53
|
$self->_log->debug(" file [$_]"); |
412
|
14
|
100
|
|
|
|
160
|
if ($_ =~ /$re/) { |
413
|
10
|
|
|
|
|
34
|
$self->_log->debug(" FOUND [$_]"); |
414
|
10
|
100
|
|
|
|
77
|
$wb = $_ unless ($matches++); # remember first occurence |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
7
|
100
|
|
|
|
22
|
unless (defined $wb) { |
419
|
1
|
|
|
|
|
3
|
$self->_log->logcarp("could not find file matching [$re]"); |
420
|
1
|
|
|
|
|
529
|
return undef; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
6
|
100
|
|
|
|
28
|
$self->_log->logwarn("non-unique match on [$re]") |
424
|
|
|
|
|
|
|
if ($matches > 1); |
425
|
|
|
|
|
|
|
|
426
|
6
|
|
|
|
|
1554
|
return $self->open($wb); |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
sub _prepend_rowid { |
431
|
110
|
|
|
110
|
|
122
|
my ($self, $ra_columns, $id)=@_; |
432
|
|
|
|
|
|
|
|
433
|
110
|
100
|
|
|
|
260
|
my $rowid = ($id == $self->title_row) ? S_RID : sprintf "%09d", $id; |
434
|
|
|
|
|
|
|
|
435
|
110
|
|
|
|
|
156
|
push @$ra_columns, $rowid; |
436
|
|
|
|
|
|
|
|
437
|
110
|
|
|
|
|
120
|
return $rowid; |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub extract { |
442
|
36
|
|
|
36
|
1
|
5114
|
my $self = shift; |
443
|
36
|
50
|
|
|
|
125
|
if (@_) { $self->sheet_name(shift); } |
|
36
|
|
|
|
|
210
|
|
444
|
36
|
50
|
|
|
|
118
|
if (@_) { $self->title_row(shift); } |
|
0
|
|
|
|
|
0
|
|
445
|
|
|
|
|
|
|
|
446
|
36
|
50
|
33
|
|
|
138
|
$self->_log->logcroak("SYNTAX: extract(sheet_name,title_row)") |
447
|
|
|
|
|
|
|
unless (defined $self->sheet_name && defined $self->title_row); |
448
|
|
|
|
|
|
|
|
449
|
36
|
|
|
|
|
154
|
$self->_log->debug(sprintf "opening [%s]", $self->sheet_name); |
450
|
|
|
|
|
|
|
|
451
|
36
|
|
|
|
|
400
|
my $ws = $self->workbook->worksheet($self->sheet_name); |
452
|
|
|
|
|
|
|
|
453
|
36
|
|
|
|
|
573
|
my ($minr, $maxr) = $ws->row_range(); |
454
|
36
|
|
|
|
|
372
|
my ($minc, $maxc) = $ws->col_range(); |
455
|
|
|
|
|
|
|
|
456
|
36
|
|
|
|
|
380
|
$self->rows($maxr); |
457
|
36
|
|
|
|
|
204
|
$self->columns($maxc + 1); |
458
|
|
|
|
|
|
|
|
459
|
36
|
100
|
|
|
|
116
|
$self->title_row($minr) # fix minimum row |
460
|
|
|
|
|
|
|
if ($self->title_row < $minr); |
461
|
|
|
|
|
|
|
|
462
|
36
|
|
|
|
|
133
|
$self->_log->debug(sprintf "sheet_name [%s] minr [%d] maxr [%d] minc [%d] maxc [%d]", |
463
|
|
|
|
|
|
|
$self->sheet_name, $minr, $maxr, $minc, $maxc); |
464
|
|
|
|
|
|
|
|
465
|
36
|
|
|
|
|
209
|
my ($subr,$subc,$value); |
466
|
0
|
|
|
|
|
0
|
my @data; |
467
|
0
|
|
|
|
|
0
|
my (@columns,@widths); |
468
|
|
|
|
|
|
|
|
469
|
36
|
|
|
|
|
119
|
for ($subr = $self->title_row; $subr <= $maxr; $subr++) { |
470
|
|
|
|
|
|
|
|
471
|
368
|
100
|
|
|
|
968
|
$self->_prepend_rowid(\@columns, $subr) |
472
|
|
|
|
|
|
|
if ($self->rowid); |
473
|
|
|
|
|
|
|
|
474
|
368
|
|
|
|
|
769
|
for ($subc = $minc; $subc <= $maxc; $subc++) { |
475
|
|
|
|
|
|
|
|
476
|
3584
|
|
|
|
|
7355
|
my $cell = $ws->get_cell($subr, $subc); |
477
|
|
|
|
|
|
|
|
478
|
3584
|
100
|
|
|
|
27844
|
if (defined $cell) { |
479
|
3552
|
100
|
|
|
|
8820
|
$value = ($self->trim) ? $self->_trim_whitespace($cell->value) : $cell->value; |
480
|
|
|
|
|
|
|
} else { |
481
|
32
|
|
|
|
|
42
|
$value = undef; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
3584
|
100
|
|
|
|
13211
|
$value = $self->_resolve_null($value, $self->null) |
485
|
|
|
|
|
|
|
if ($self->force_null); |
486
|
|
|
|
|
|
|
|
487
|
3584
|
|
|
|
|
7803
|
push @columns, $value; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
# adjust widths, including rowid column |
491
|
368
|
|
|
|
|
343
|
$subc = 0; |
492
|
368
|
|
|
|
|
474
|
for $value (@columns) { |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
# calculate width, ignoring title_row |
495
|
|
|
|
|
|
|
|
496
|
3694
|
100
|
|
|
|
8891
|
if ($subr == $self->title_row) { |
497
|
346
|
|
|
|
|
371
|
$widths[$subc] = 0; |
498
|
|
|
|
|
|
|
} else { |
499
|
3348
|
100
|
100
|
|
|
11149
|
$widths[$subc] = length($value) |
500
|
|
|
|
|
|
|
if (defined($value) && |
501
|
|
|
|
|
|
|
length($value) > $widths[$subc]); |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
|
504
|
3694
|
|
|
|
|
3946
|
$subc++; |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
368
|
|
|
|
|
966
|
$self->_log->debug(sprintf '@columns [%s]', Dumper(\@columns)); |
508
|
368
|
|
|
|
|
26592
|
$self->_log->debug(sprintf '@widths [%s]', Dumper(\@widths)); |
509
|
|
|
|
|
|
|
|
510
|
368
|
100
|
|
|
|
22789
|
if ($subr == $self->title_row) { |
511
|
36
|
|
|
|
|
195
|
$self->titles([ @columns ]); |
512
|
|
|
|
|
|
|
} else { |
513
|
332
|
|
|
|
|
936
|
push @data, [ @columns ]; |
514
|
|
|
|
|
|
|
} |
515
|
368
|
|
|
|
|
1079
|
@columns = (); |
516
|
|
|
|
|
|
|
} |
517
|
36
|
|
|
|
|
216
|
$self->widths([ @widths ]); |
518
|
|
|
|
|
|
|
|
519
|
36
|
|
|
|
|
85
|
@widths = $ws = (); |
520
|
|
|
|
|
|
|
|
521
|
36
|
|
|
|
|
292
|
return @data; |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
sub colid2title { |
526
|
4
|
|
|
4
|
1
|
9
|
my ($self,$colid)=@_; |
527
|
|
|
|
|
|
|
|
528
|
4
|
50
|
|
|
|
16
|
$self->_log->logcroak("SYNTAX: colid2title2(colid)") |
529
|
|
|
|
|
|
|
unless (defined $colid); |
530
|
|
|
|
|
|
|
|
531
|
4
|
|
|
|
|
23
|
$self->_log->debug("colid [$colid]"); |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
return undef |
534
|
4
|
50
|
|
|
|
38
|
if ($colid < 0); |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
return undef |
537
|
4
|
100
|
|
|
|
5
|
unless ($colid < scalar @{ $self->titles }); |
|
4
|
|
|
|
|
18
|
|
538
|
|
|
|
|
|
|
|
539
|
2
|
|
|
|
|
10
|
return $self->titles->[$colid]; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
sub title2colid { |
544
|
44
|
|
|
44
|
1
|
69
|
my ($self,$title)=@_; |
545
|
|
|
|
|
|
|
|
546
|
44
|
50
|
|
|
|
93
|
$self->_log->logcroak("SYNTAX: title2colid(title)") |
547
|
|
|
|
|
|
|
unless (defined $title); |
548
|
|
|
|
|
|
|
|
549
|
44
|
|
|
|
|
124
|
$self->_log->debug("title [$title] "); |
550
|
|
|
|
|
|
|
|
551
|
44
|
|
|
|
|
189
|
my $tmax = scalar @{ $self->titles }; |
|
44
|
|
|
|
|
118
|
|
552
|
|
|
|
|
|
|
|
553
|
44
|
|
|
|
|
139
|
for (my $tsub = 0; $tsub < $tmax; $tsub++) { |
554
|
294
|
100
|
|
|
|
831
|
if ($self->titles->[$tsub] =~ /$title/) { |
555
|
30
|
|
|
|
|
95
|
$self->_log->debug("match at colid $tsub"); |
556
|
30
|
|
|
|
|
186
|
return $tsub; |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
} |
559
|
14
|
|
|
|
|
54
|
$self->_log->debug("NO MATCH"); |
560
|
|
|
|
|
|
|
|
561
|
14
|
|
|
|
|
90
|
return undef; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
sub _trim_whitespace { |
566
|
1526
|
|
|
1526
|
|
5288
|
my ($self,$s_value)=@_; |
567
|
|
|
|
|
|
|
|
568
|
1526
|
50
|
|
|
|
2207
|
if (defined $s_value) { |
569
|
1526
|
|
|
|
|
3360
|
$self->_log->debug("s_value [$s_value]"); |
570
|
|
|
|
|
|
|
|
571
|
1526
|
|
|
|
|
7909
|
$s_value =~ s/^[[:cntrl:][:space:]]+//; # trim leading |
572
|
1526
|
|
|
|
|
2194
|
$s_value =~ s/[[:cntrl:][:space:]]+$//; # trim trailing |
573
|
|
|
|
|
|
|
|
574
|
1526
|
|
|
|
|
3538
|
$self->_log->debug("after s_value [$s_value]"); |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
1526
|
|
|
|
|
7464
|
return $s_value; |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
sub _resolve_null { |
582
|
440
|
|
|
440
|
|
434
|
my ($self, $s_value, $s_null)=@_; |
583
|
|
|
|
|
|
|
|
584
|
440
|
100
|
|
|
|
787
|
$self->_log->debug(sprintf "s_value [%s] s_null [%s]", |
|
|
50
|
|
|
|
|
|
585
|
|
|
|
|
|
|
(defined $s_value) ? $s_value : "not defined", |
586
|
|
|
|
|
|
|
(defined $s_null) ? $s_null : "not defined", |
587
|
|
|
|
|
|
|
); |
588
|
|
|
|
|
|
|
|
589
|
440
|
100
|
|
|
|
1871
|
if (defined $s_value) { |
590
|
436
|
100
|
|
|
|
656
|
$s_value = $s_null |
591
|
|
|
|
|
|
|
if ($s_value eq ""); |
592
|
|
|
|
|
|
|
} else { |
593
|
4
|
|
|
|
|
5
|
$s_value = $s_null; |
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
|
596
|
440
|
|
|
|
|
470
|
return $s_value; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
sub _array_to_hash { |
601
|
4
|
|
|
4
|
|
6
|
my $self = shift; |
602
|
4
|
|
|
|
|
6
|
my @data; |
603
|
|
|
|
|
|
|
|
604
|
4
|
|
|
|
|
12
|
for my $row (@_) { |
605
|
40
|
|
|
|
|
136
|
$self->_log->debug(sprintf '$row [%s]', Dumper($row)); |
606
|
|
|
|
|
|
|
|
607
|
40
|
|
|
|
|
2353
|
my %data; |
608
|
40
|
|
|
|
|
68
|
my $unique = 0; |
609
|
40
|
|
|
|
|
59
|
my $m_value = scalar(@$row); |
610
|
|
|
|
|
|
|
|
611
|
40
|
|
|
|
|
99
|
for (my $ss_value = 0; $ss_value < $m_value; $ss_value++) { |
612
|
|
|
|
|
|
|
|
613
|
260
|
|
|
|
|
632
|
my $column = $self->titles->[$ss_value]; |
614
|
260
|
|
|
|
|
289
|
my $value = $row->[$ss_value]; |
615
|
|
|
|
|
|
|
|
616
|
260
|
100
|
|
|
|
367
|
my $key = (exists $data{$column}) ? $column . $unique++ : $column; |
617
|
260
|
|
|
|
|
565
|
$data{$key} = $value; |
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
|
620
|
40
|
|
|
|
|
109
|
$self->_log->debug(sprintf 'data [%s]', Dumper(\%data)); |
621
|
|
|
|
|
|
|
|
622
|
40
|
|
|
|
|
2687
|
push @data, { %data }; |
623
|
|
|
|
|
|
|
|
624
|
40
|
|
|
|
|
127
|
%data = (); |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
4
|
|
|
|
|
26
|
return @data; |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
sub extract_hash { |
632
|
2
|
|
|
2
|
1
|
5
|
my $self = shift; |
633
|
|
|
|
|
|
|
|
634
|
2
|
50
|
|
|
|
8
|
$self->_log->logcroak("SYNTAX: extract_hash(sheet_name,[title_row])") |
635
|
|
|
|
|
|
|
unless (@_ > 0); |
636
|
|
|
|
|
|
|
|
637
|
2
|
|
|
|
|
7
|
return $self->_array_to_hash($self->extract(@_)); |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
sub select_hash { |
642
|
2
|
|
|
2
|
1
|
9344
|
my $self = shift; |
643
|
2
|
|
|
|
|
5
|
my $clause = shift; |
644
|
|
|
|
|
|
|
|
645
|
2
|
50
|
|
|
|
11
|
$self->_log->logcroak("SYNTAX: select_hash(clause,[sheet_name,title_row])") |
646
|
|
|
|
|
|
|
unless (@_ > 0); |
647
|
|
|
|
|
|
|
|
648
|
2
|
|
|
|
|
10
|
return $self->_array_to_hash($self->select($clause, @_)); |
649
|
|
|
|
|
|
|
} |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
sub select { |
653
|
14
|
|
|
14
|
1
|
9667
|
my $self = shift; |
654
|
14
|
|
|
|
|
28
|
my $clause = shift; |
655
|
|
|
|
|
|
|
|
656
|
14
|
50
|
|
|
|
50
|
$self->_log->logcroak("SYNTAX: select(clause,[sheet_name,title_row])") |
657
|
|
|
|
|
|
|
unless (defined $clause); |
658
|
|
|
|
|
|
|
|
659
|
14
|
|
|
|
|
61
|
my @pre = $self->extract(@_); |
660
|
14
|
|
|
|
|
29
|
my (@post, @id); |
661
|
0
|
|
|
|
|
0
|
my (@columns, @widths); |
662
|
|
|
|
|
|
|
|
663
|
14
|
100
|
|
|
|
46
|
$clause = join(',', S_RID, $clause) |
664
|
|
|
|
|
|
|
if ($self->rowid); |
665
|
|
|
|
|
|
|
|
666
|
14
|
|
|
|
|
71
|
for my $column (split(/,/, $clause)) { |
667
|
40
|
|
|
|
|
3079
|
$self->_log->debug("column [$column]"); |
668
|
|
|
|
|
|
|
|
669
|
40
|
|
|
|
|
241
|
my $id = $self->title2colid($column); |
670
|
|
|
|
|
|
|
|
671
|
40
|
100
|
|
|
|
72
|
if (defined $id) { |
672
|
28
|
|
|
|
|
43
|
push @id, $id; |
673
|
28
|
|
|
|
|
33
|
push @columns, $column; |
674
|
28
|
|
|
|
|
69
|
push @widths, $self->widths->[$id]; |
675
|
|
|
|
|
|
|
} else { |
676
|
12
|
|
|
|
|
33
|
$self->_log->logwarn("invalid column [$column]"); |
677
|
|
|
|
|
|
|
} |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
|
680
|
14
|
|
|
|
|
905
|
$self->_log->debug(sprintf '@id [%s]', Dumper(\@id)); |
681
|
|
|
|
|
|
|
|
682
|
14
|
100
|
|
|
|
857
|
my $f_no_columns = ($self->rowid) ? 1 : 0; |
683
|
|
|
|
|
|
|
|
684
|
14
|
100
|
|
|
|
47
|
unless (scalar(@columns) == $f_no_columns) { # no columns, thus no rows |
685
|
10
|
|
|
|
|
24
|
for my $row (@pre) { |
686
|
100
|
|
|
|
|
422
|
$self->_log->debug(sprintf 'row [%s]', Dumper($row)); |
687
|
|
|
|
|
|
|
|
688
|
100
|
|
|
|
|
6455
|
my @wanted = (); |
689
|
|
|
|
|
|
|
|
690
|
100
|
|
|
|
|
158
|
for my $id (@id) { |
691
|
260
|
|
|
|
|
365
|
push @wanted, $row->[$id]; |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
|
694
|
100
|
|
|
|
|
379
|
$self->_log->debug(sprintf '@wanted [%s]', Dumper(\@wanted)); |
695
|
|
|
|
|
|
|
|
696
|
100
|
50
|
|
|
|
5001
|
push @post, [ @wanted ] |
697
|
|
|
|
|
|
|
if (scalar(@wanted)); # account for null case |
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
14
|
|
|
|
|
59
|
$self->_log->debug(sprintf '@columns [%s]', Dumper(\@columns)); |
702
|
14
|
|
|
|
|
664
|
$self->_log->debug(sprintf '@widths [%s]', Dumper(\@widths)); |
703
|
|
|
|
|
|
|
|
704
|
14
|
|
|
|
|
703
|
$self->titles([ @columns ]); |
705
|
14
|
|
|
|
|
65
|
$self->widths([ @widths ]); |
706
|
|
|
|
|
|
|
|
707
|
14
|
|
|
|
|
217
|
return @post; |
708
|
|
|
|
|
|
|
} |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
DESTROY { |
712
|
24
|
|
|
24
|
|
68830
|
my $self = shift; |
713
|
24
|
|
|
|
|
31
|
-- ${ $self->{_n_objects} }; |
|
24
|
|
|
|
|
3078
|
|
714
|
|
|
|
|
|
|
}; |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
#END { } |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
1; |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
__END__ |