Excel-Template-XLSX
view release on metacpan or search on metacpan
lib/Excel/Template/XLSX.pm view on Meta::CPAN
$self->{_dim_rowmin} = undef;
$self->{_dim_rowmax} = undef;
$self->{_dim_colmin} = undef;
$self->{_dim_colmax} = undef;
$sheet->set_default_row($default_row_height);
$twig->purge;
},
# Default row height
'sheetFormatPr' => sub {
my ( $twig, $format ) = @_;
$default_row_height //= $format->att('defaultRowHeight');
$default_column_width //= $format->att('baseColWidth');
$sheet->set_default_row($default_row_height);
$twig->purge;
},
# Sets (one or more) column widths
'col' => sub {
my ( $twig, $col ) = @_;
my $min = $col->att('min') - 1;
my $max = $col->att('max') - 1;
$sheet->set_column( $min, $max, $col->att('width') );
$twig->purge;
},
'row' => sub {
my ( $twig, $row ) = @_;
# ?? just sets row height. No formatting yet
# set_row( $row, $height, $format, $hidden, $level, $collapsed )
$sheet->set_row( $row->att('r') - 1, $row->att('ht') );
$twig->purge;
},
'sheetView/selection' => sub {
my ( $twig, $selection ) = @_;
my $range = $selection->att('sqref')
// $selection->att('activeCell') // 'A1';
$sheet->set_selection($range);
$twig->purge;
},
'sheetPr/tabColor' => sub {
my ( $twig, $tab_color ) = @_;
$sheet->set_tab_color( $tab_color->att('rgb') );
$twig->purge;
}
} # return hashref
}
###############################################################################
sub _parse_sheet_pass2 {
=head2 _parse_sheet_pass2
Parses cell contents (first by row, then by column). Cells can contain
inline strings, string references, direct string values, formulas,
and hyperlinks. Each cell may also contain formatting information.
The format is in an index to formatting for borders, shading, alignment,
font, and number formats.
=cut
my $self = shift;
my ($sheet) = @_;
return {
'sheetData/row' => sub {
my ( $twig, $row_elt ) = @_;
my $sheet_idx = $sheet->{_index};
for my $cell ( $row_elt->children('c') ) {
my $string_index = 0;
my $a1 = $cell->att('r'); # Cell Address
my $t = $cell->att('t') || 'n'; # Cell Type
my $s = $cell->att('s') // 0; # Cell Format Index (e.g. styles)
my ($r, $c) = $self->_cell_to_row_col($a1);
$self->{CELL_FORMAT}->[$r][$c] = $s;
my $val_xml
= $t eq 'inlineStr'
? $cell->first_child('is')->first_child('t')
: $cell->first_child('v');
my $val = $val_xml ? $val_xml->text() : undef;
my $format_idx = $s;
my $format = $self->{FORMATS}[$format_idx];
# Formatted cell, no contents
if ( !defined($val) ) {
$sheet->write_blank($a1, $format);
next;
}
if ( $t eq 's' ) {
$string_index = $val;
$val = $self->{SHARED_STRINGS}[$val];
my $is_array = ref($val) eq 'ARRAY';
my @aval = $is_array ? @$val : ($val);
if ( my $ref = $self->{MERGED_RANGES}{$sheet_idx}{$a1} ) {
my $type = $is_array ? 'rich_string' : 'string';
$sheet->merge_range_type($type, $ref, @aval, $format );
$self->{MERGED_RANGES}{$sheet_idx}{$a1} = 0; # Flag it as used. Handle unused ranges at end
next;
}
# Special case for multiple formats in a cell
# see _parse_shared_strings for rPr nodes
if ( $is_array ) {
$sheet->write_rich_string( $a1, @aval );
next;
}
if ( my $url = $self->{HYPERLINKS}{$a1} ) {
$sheet->write_url( $a1, $url, $format, $val );
next;
}
$sheet->write_string( $a1, $val, $format );
next;
}
# In-line string (not seen in practice)
elsif ( $t eq 'str' ) {
$val = '=' . $cell->first_child('f')->text();
}
# Formulas
elsif ( $t eq 'n' ) {
if ( my $form_child = $cell->first_child('f') ) {
my $is_array = $form_child->att('t');
my $ref = $form_child->att('ref');
my $formula = $form_child->text() // q[="No Formula Found"];
if ($is_array and $ref) {
$sheet->write_array_formula( $ref, "=${formula}", $format, $val );
}
else {
if ( my $ref = $self->{MERGED_RANGES}{$sheet_idx}{$a1} ) {
$sheet->merge_range_type('formula', $ref, "=${formula}", $format, $val);
$self->{MERGED_RANGES}{$sheet_idx}{$a1} = 0; # Flag it as used. Handle unused ranges at end
} else {
$sheet->write_formula( $a1, "=${formula}", $format, $val );
}
}
next;
}
}
elsif ( $t eq 'b' ) {
$val = $val ? "TRUE" : "FALSE";
}
elsif ( $t eq 'e' ) {
}
elsif ( $t eq 'str' || $t eq 'inlineStr' ) {
}
else {
warn "unimplemented type $t found in cell $a1"; # XXX
}
$sheet->write( $a1, $val, $format );
}
$twig->purge;
}
};
}
###############################################################################
sub _parse_final_pass {
=head2 _parse_final_pass
Make a final pass to process merge_ranges that do not have any cell contents.
This is it for now, but more may be added in the future.
=cut
my $self = shift;
my ($sheet) = @_;
my $idx = $sheet->{_index};
foreach my $r (keys %{ $self->{MERGED_RANGES}->{ $idx } } ) {
my $ref = $self->{MERGED_RANGES}->{ $idx }->{$r};
next unless $ref; # Only process merged ranges that have not been referenced yet.
$sheet->merge_range_type('blank', $ref, $self->{FORMATS}[0]);
my ($first, $last) = split('\:', $ref);
my ($rf, $cf) = $self->_cell_to_row_col($first);
my ($rl, $cl) = $self->_cell_to_row_col($last);
for my $r ($rf .. $rl) {
for my $c ($cf .. $cl) {
my $fid = $self->{CELL_FORMAT}->[$r][$c] // 0;
$sheet->write_blank($r, $c, $self->{FORMATS}[$fid] );
}
}
}
}
###############################################################################
sub _parse_styles {
=head2 _parse_styles
Parses style information.
Parses number formats directly. Calls subroutines to parse
( run in 0.511 second using v1.01-cache-2.11-cpan-5837b0d9d2c )