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