The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Spreadsheet::ParseExcel::Stream::XLSX;

use strict;
use warnings;

our $VERSION = '0.09';

sub new {
  my ($class, $file, $opts) = @_;
  $opts ||= {};
  my @converter = $opts->{Converter} ? $opts->{Converter} : ();
  require Spreadsheet::XLSX;
  # Silence warnings in XLSX library
  my $xls = do {
    local $SIG{__WARN__} = sub {};
    Spreadsheet::XLSX->new($file, @converter);
  };
  my @sheets = @{$xls->{Worksheet}};
  bless {
    XLS    => $xls,
    SHEETS => \@sheets,
    ROWS   => [],
  }, $class;
}

sub sheet {
  my $self = shift;
  my $sheet = shift @{$self->{SHEETS}} or return;
  my $min_row = $sheet->{MinRow};
  my $max_row = $sheet->{MaxRow} || $min_row;
  my $min_col = $sheet->{MinCol};
  my $max_col = $sheet->{MaxCol} || $min_col;
  $self->{CURR_SHEET} = {
    SHEET   => $sheet,
    MAX_ROW => $max_row,
    MAX_COL => $max_col,
    CURR_ROW => $min_row,
  };
  return $self;
}

sub name { $_[0]->{CURR_SHEET}{SHEET}{Name} }

sub row {
  my ( $self, $prev_row, $cell_func ) = @_;

  # Default to formatted value
  $cell_func ||= sub { $_[0]->value() };

  my $curr_sheet_data = $self->{CURR_SHEET};
  my $offset = $prev_row ? 1 : 0;
  my $row = $curr_sheet_data->{CURR_ROW} - $offset;
  return if $row > $curr_sheet_data->{MAX_ROW};
  my $sheet = $curr_sheet_data->{SHEET};
  
  my $row_data = $sheet->{Cells}[$row];
  my @data = map {
    defined($row_data->[$_]) ? $cell_func->($row_data->[$_]) : ''
  } 0..$curr_sheet_data->{MAX_COL};
  $curr_sheet_data->{CURR_ROW}++ unless $prev_row;
  if ( $self->{BIND} ) {
    $$_ = shift @data for @{$self->{BIND}};
    return 1;
  }
  return \@data;
}

sub unformatted {
  my ( $self, $prev_row ) = @_;
  $self->row($prev_row, sub { $_[0]->unformatted() } );
}

sub next_row {
  my ( $self, $prev_row ) = @_;
  $self->row($prev_row, sub { $_[0] } );
}

sub bind_columns {
  my $self = shift;
  $self->{BIND} = [ @_ ];
}

sub unbind_columns {
  delete $_[0]->{BIND};
}

1;

__END__

=head1 NAME

Spreadsheet::ParseExcel::Stream::XLSX - Simple interface to XLSX Excel data

=head1 SYNOPSIS

  my $xls = Spreadsheet::ParseExcel::Stream::XLSX->new($xlsx_file, \%options);
  while ( my $sheet = $xls->sheet() ) {
    while ( my $row = $sheet->row ) {
      my @data = @$row;
    }
  }

=head1 DESCRIPTION

See L<Spreadsheet::ParseExcel::Stream>.

=head1 AUTHOR

Douglas Wilson, E<lt>dougw@cpan.org<gt>

=head1 COPYRIGHT AND LICENSE

This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

=cut