File Coverage

blib/lib/Catmandu/Importer/XLSX.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Catmandu::Importer::XLSX;
2              
3             our $VERSION = '0.08';
4              
5 3     3   3270 use namespace::clean;
  3         6  
  3         24  
6 3     3   451 use Catmandu::Sane;
  3         6  
  3         22  
7 3     3   1586 use Encode qw(decode);
  3         10547  
  3         304  
8 3     3   2625 use Spreadsheet::ParseXLSX;
  0            
  0            
9             use Spreadsheet::ParseExcel::Utility qw(int2col);
10             use Moo;
11              
12             with 'Catmandu::Importer';
13              
14             has xlsx => (is => 'ro', builder => '_build_xlsx');
15             has header => (is => 'ro', default => sub { 1 });
16             has columns => (is => 'ro' , default => sub { 0 });
17             has fields => (
18             is => 'rw',
19             coerce => sub {
20             my $fields = $_[0];
21             if (ref $fields eq 'ARRAY') { return $fields }
22             if (ref $fields eq 'HASH') { return [sort keys %$fields] }
23             return [split ',', $fields];
24             },
25             );
26             has worksheet => (is => 'ro' , default => sub { 0 });
27             has _n => (is => 'rw', default => sub { 0 });
28             has _row_min => (is => 'rw');
29             has _row_max => (is => 'rw');
30             has _col_min => (is => 'rw');
31             has _col_max => (is => 'rw');
32              
33             sub BUILD {
34             my $self = shift;
35              
36             if ( $self->header ) {
37             if ( $self->fields ) {
38             $self->{_n}++;
39             }
40             elsif ( $self->columns ) {
41             $self->fields([$self->_get_cols]);
42             $self->{_n}++;
43             }
44             else {
45             $self->fields([$self->_get_row]);
46             $self->{_n}++;
47             }
48             }
49             else {
50             if ( !$self->fields || $self->columns ) {
51             $self->fields([$self->_get_cols]);
52             }
53             }
54             }
55              
56             sub _build_xlsx {
57             my ($self) = @_;
58             my $parser = Spreadsheet::ParseXLSX->new();
59             my $xlsx = $parser->parse( $self->file ) or Catmandu::Error->throw("could not parse file \"$self->{file}\": " . $parser->error());
60              
61             $xlsx = $xlsx->worksheet($self->worksheet) or Catmandu::Error->throw("worksheet $self->{worksheet} does not exist.");
62             ($self->{_row_min}, $self->{_row_max}) = $xlsx->row_range();
63             ($self->{_col_min}, $self->{_col_max}) = $xlsx->col_range();
64             return $xlsx;
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             my ($self) = @_;
86             my @row;
87             for my $col ($self->_col_min .. $self->_col_max) {
88             my $cell = $self->xlsx->get_cell($self->_n, $col);
89             if ($cell) {
90             push(@row,$cell->value());
91             }
92             else{
93             push(@row, undef);
94             }
95             }
96             return @row;
97             }
98              
99             sub _get_cols {
100             my ($self) = @_;
101             my @row;
102             for my $col ( $self->_col_min .. $self->_col_max ) {
103              
104             if (!$self->header || $self->columns) {
105             push(@row,int2col($col));
106             }
107             else {
108             my $cell = $self->xlsx->get_cell($self->_n, $col);
109             if ($cell) {
110             push(@row,$cell->value());
111             }
112             else{
113             push(@row, undef);
114             }
115             }
116             }
117             return @row;
118             }
119              
120              
121             =head1 NAME
122              
123             Catmandu::Importer::XLSX - Package that imports XLSX files
124              
125             =head1 SYNOPSIS
126              
127             # On the command line
128             $ catmandu convert XLSX < ./t/test.xlsx
129             $ catmandu convert XLSX --header 0 < ./t/test.xlsx
130             $ catmandu convert XLSX --fields 1,2,3 < ./t/test.xlsx
131             $ catmandu convert XLSX --columns 1 < ./t/test.xlsx
132             $ catmandu convert XLSX --worksheet 1 < ./t/test.xlsx
133              
134             # Or in Perl
135             use Catmandu::Importer::XLSX;
136              
137             my $importer = Catmandu::Importer::XLSX->new(file => "./t/test.xlsx");
138              
139             my $n = $importer->each(sub {
140             my $hashref = $_[0];
141             # ...
142             });
143              
144             =head1 DESCRIPTION
145              
146             L importer for XLSX files.
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             =item worksheet
176              
177             If the Excel workbook contains more than one worksheet, you can select a specific worksheet by its index number (0,1,2,...). Default: 0.
178              
179             =back
180              
181             =head1 SEE ALSO
182              
183             L, L, L, L.
184              
185             =cut
186              
187             1;