File Coverage

blib/lib/Catmandu/Importer/XLS.pm
Criterion Covered Total %
statement 46 50 92.0
branch 11 16 68.7
condition 3 6 50.0
subroutine 9 9 100.0
pod 0 1 0.0
total 69 82 84.1


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