File Coverage

blib/lib/Catmandu/Importer/XLS.pm
Criterion Covered Total %
statement 46 50 92.0
branch 12 18 66.6
condition 3 6 50.0
subroutine 9 9 100.0
pod 0 1 0.0
total 70 84 83.3


line stmt bran cond sub pod time code
1             package Catmandu::Importer::XLS;
2            
3             our $VERSION = '0.07';
4            
5 3     3   34954 use namespace::clean;
  3         18021  
  3         21  
6 3     3   1101 use Catmandu::Sane;
  3         156885  
  3         26  
7 3     3   4636 use Spreadsheet::ParseExcel;
  3         170680  
  3         134  
8 3     3   35 use Spreadsheet::ParseExcel::Utility qw(int2col);
  3         7  
  3         208  
9 3     3   20 use Moo;
  3         9  
  3         30  
10            
11             with 'Catmandu::Importer';
12            
13             has xls => (is => 'ro', builder => '_build_xls');
14             has header => (is => 'ro', default => sub { 1 });
15             has columns => (is => 'ro' , default => sub { 0 });
16             has fields => (
17             is => 'rw',
18             coerce => sub {
19             my $fields = $_[0];
20             if (ref $fields eq 'ARRAY') { return $fields }
21             if (ref $fields eq 'HASH') { return [sort keys %$fields] }
22             return [split ',', $fields];
23             },
24             );
25             has worksheet => (is => 'ro' , default => sub { 0 });
26             has _n => (is => 'rw', default => sub { 0 });
27             has _row_min => (is => 'rw');
28             has _row_max => (is => 'rw');
29             has _col_min => (is => 'rw');
30             has _col_max => (is => 'rw');
31            
32             sub BUILD {
33 10     10 0 115 my $self = shift;
34            
35 10 100       63 if ( $self->header ) {
36 8 100       149 if ( $self->fields ) {
    100          
37 1         28 $self->{_n}++;
38             }
39             elsif ( $self->columns ) {
40 1         13 $self->fields([$self->_get_cols]);
41 1         31 $self->{_n}++;
42             }
43             else {
44 6         1464 $self->fields([$self->_get_row]);
45 6         171 $self->{_n}++;
46             }
47             }
48             else {
49 2 50 33     47 if ( !$self->fields || $self->columns ) {
50 2         26 $self->fields([$self->_get_cols]);
51             }
52             }
53             }
54            
55             sub _build_xls {
56 10     10   156 my ($self) = @_;
57 10         88 my $parser = Spreadsheet::ParseExcel->new();
58 10 50       1789 my $xls = $parser->parse( $self->file ) or Catmandu::Error->throw("could not parse file \"$self->{file}\": " . $parser->error());
59            
60             # process only first worksheet
61 10 50       742590 $xls = $xls->worksheet($self->worksheet) or Catmandu::Error->throw("worksheet $self->{worksheet} does not exist.");
62 10         231 ($self->{_row_min}, $self->{_row_max}) = $xls->row_range();
63 10         125 ($self->{_col_min}, $self->{_col_max}) = $xls->col_range();
64 10         509 return $xls;
65             }
66            
67             sub generator {
68             my ($self) = @_;
69             sub {
70             while ($self->_n <= $self->_row_max) {
71             my @data = $self->_get_row();
72             $self->{_n}++;
73             my @fields = @{$self->fields()};
74             my %hash = map {
75             my $key = shift @fields;
76             defined $_ ? ($key => $_) : ()
77             } @data;
78             return \%hash;
79             }
80             return;
81             }
82             }
83            
84             sub _get_row {
85 130     130   179 my ($self) = @_;
86 130         138 my @row;
87 130         351 for my $col ( $self->_col_min .. $self->_col_max ) {
88 366         2010 my $cell = $self->xls->get_cell( $self->_n, $col );
89 366 100       3382 if ($cell) {
90 282         725 push(@row,$cell->value());
91             }
92             else{
93 84         155 push(@row, undef);
94             }
95             }
96 130         731 return @row;
97             }
98            
99             sub _get_cols {
100 3     3   7 my ($self) = @_;
101            
102 3         6 my @row;
103 3         18 for my $col ( $self->_col_min .. $self->_col_max ) {
104            
105 8 50 66     83 if (!$self->header || $self->columns) {
106 8         30 push(@row,int2col($col));
107             }
108             else {
109 0         0 my $cell = $self->xls->get_cell( $self->_n, $col );
110 0 0       0 if ($cell) {
111 0         0 push(@row,$cell->value());
112             }
113             else{
114 0         0 push(@row, undef);
115             }
116             }
117             }
118 3         92 return @row;
119             }
120            
121             =head1 NAME
122            
123             Catmandu::Importer::XLS - Package that imports XLS files
124            
125             =head1 SYNOPSIS
126            
127             # On the command line
128             $ catmandu convert XLS < ./t/test.xls
129             $ catmandu convert XLS --header 0 < ./t/test.xls
130             $ catmandu convert XLS --fields 1,2,3 < ./t/test.xls
131             $ catmandu convert XLS --columns 1 < ./t/test.xls
132             $ catmandu convert XLS --worksheet 1 < ./t/test.xls
133            
134             # Or in Perl
135             use Catmandu::Importer::XLS;
136            
137             my $importer = Catmandu::Importer::XLS->new(file => "./t/test.xls");
138            
139             my $n = $importer->each(sub {
140             my $hashref = $_[0];
141             # ...
142             });
143            
144             =head1 DESCRIPTION
145            
146             L importer for XLS files.
147            
148             Only the first worksheet from the Excel workbook is imported.
149            
150             =head1 METHODS
151            
152             This module inherits all methods of L and by this
153             L.
154            
155             =head1 CONFIGURATION
156            
157             In addition to the configuration provided by L (C,
158             C, etc.) the importer can be configured with the following parameters:
159            
160             =over
161            
162             =item header
163            
164             By default object fields are read from the XLS header line. If no header
165             line is avaiable object fields are named as column coordinates (A,B,C,...). Default: 1.
166            
167             =item fields
168            
169             Provide custom object field names as array, hash reference or comma-
170             separated list.
171            
172             =item columns
173            
174             When the 'columns' option is provided, then the object fields are named as
175             column coordinates (A,B,C,...). Default: 0.
176            
177             =item worksheet
178            
179             If the Excel workbook contains more than one worksheet, you can select a specific worksheet by its index number (0,1,2,...). Default: 0.
180            
181             =back
182            
183             =head1 SEE ALSO
184            
185             L, L, L, L.
186            
187             =cut
188            
189             1;