Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,454 @@
package Excel::Writer::XLSX::Package::App;
###############################################################################
#
# App - A class for writing the Excel XLSX app.xml file.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use warnings;
use Carp;
use Excel::Writer::XLSX::Package::XMLwriter;
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
our $VERSION = '1.07';
###############################################################################
#
# Public and private API methods.
#
###############################################################################
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my $class = shift;
my $fh = shift;
my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh );
$self->{_part_names} = [];
$self->{_heading_pairs} = [];
$self->{_properties} = {};
bless $self, $class;
return $self;
}
###############################################################################
#
# _assemble_xml_file()
#
# Assemble and write the XML file.
#
sub _assemble_xml_file {
my $self = shift;
$self->xml_declaration;
$self->_write_properties();
$self->_write_application();
$self->_write_doc_security();
$self->_write_scale_crop();
$self->_write_heading_pairs();
$self->_write_titles_of_parts();
$self->_write_manager();
$self->_write_company();
$self->_write_links_up_to_date();
$self->_write_shared_doc();
$self->_write_hyperlink_base();
$self->_write_hyperlinks_changed();
$self->_write_app_version();
$self->xml_end_tag( 'Properties' );
# Close the XML writer filehandle.
$self->xml_get_fh()->close();
}
###############################################################################
#
# _add_part_name()
#
# Add the name of a workbook Part such as 'Sheet1' or 'Print_Titles'.
#
sub _add_part_name {
my $self = shift;
my $part_name = shift;
push @{ $self->{_part_names} }, $part_name;
}
###############################################################################
#
# _add_heading_pair()
#
# Add the name of a workbook Heading Pair such as 'Worksheets', 'Charts' or
# 'Named Ranges'.
#
sub _add_heading_pair {
my $self = shift;
my $heading_pair = shift;
return unless $heading_pair->[1]; # Ignore empty pairs such as chartsheets.
my @vector = (
[ 'lpstr', $heading_pair->[0] ], # Data name
[ 'i4', $heading_pair->[1] ], # Data size
);
push @{ $self->{_heading_pairs} }, @vector;
}
###############################################################################
#
# _set_properties()
#
# Set the document properties.
#
sub _set_properties {
my $self = shift;
my $properties = shift;
$self->{_properties} = $properties;
}
###############################################################################
#
# Internal methods.
#
###############################################################################
###############################################################################
#
# XML writing methods.
#
###############################################################################
###############################################################################
#
# _write_properties()
#
# Write the <Properties> element.
#
sub _write_properties {
my $self = shift;
my $schema = 'http://schemas.openxmlformats.org/officeDocument/2006/';
my $xmlns = $schema . 'extended-properties';
my $xmlns_vt = $schema . 'docPropsVTypes';
my @attributes = (
'xmlns' => $xmlns,
'xmlns:vt' => $xmlns_vt,
);
$self->xml_start_tag( 'Properties', @attributes );
}
###############################################################################
#
# _write_application()
#
# Write the <Application> element.
#
sub _write_application {
my $self = shift;
my $data = 'Microsoft Excel';
$self->xml_data_element( 'Application', $data );
}
###############################################################################
#
# _write_doc_security()
#
# Write the <DocSecurity> element.
#
sub _write_doc_security {
my $self = shift;
my $data = 0;
$self->xml_data_element( 'DocSecurity', $data );
}
###############################################################################
#
# _write_scale_crop()
#
# Write the <ScaleCrop> element.
#
sub _write_scale_crop {
my $self = shift;
my $data = 'false';
$self->xml_data_element( 'ScaleCrop', $data );
}
###############################################################################
#
# _write_heading_pairs()
#
# Write the <HeadingPairs> element.
#
sub _write_heading_pairs {
my $self = shift;
$self->xml_start_tag( 'HeadingPairs' );
$self->_write_vt_vector( 'variant', $self->{_heading_pairs} );
$self->xml_end_tag( 'HeadingPairs' );
}
###############################################################################
#
# _write_titles_of_parts()
#
# Write the <TitlesOfParts> element.
#
sub _write_titles_of_parts {
my $self = shift;
$self->xml_start_tag( 'TitlesOfParts' );
my @parts_data;
for my $part_name ( @{ $self->{_part_names} } ) {
push @parts_data, [ 'lpstr', $part_name ];
}
$self->_write_vt_vector( 'lpstr', \@parts_data );
$self->xml_end_tag( 'TitlesOfParts' );
}
###############################################################################
#
# _write_vt_vector()
#
# Write the <vt:vector> element.
#
sub _write_vt_vector {
my $self = shift;
my $base_type = shift;
my $data = shift;
my $size = @$data;
my @attributes = (
'size' => $size,
'baseType' => $base_type,
);
$self->xml_start_tag( 'vt:vector', @attributes );
for my $aref ( @$data ) {
$self->xml_start_tag( 'vt:variant' ) if $base_type eq 'variant';
$self->_write_vt_data( @$aref );
$self->xml_end_tag( 'vt:variant' ) if $base_type eq 'variant';
}
$self->xml_end_tag( 'vt:vector' );
}
##############################################################################
#
# _write_vt_data()
#
# Write the <vt:*> elements such as <vt:lpstr> and <vt:if>.
#
sub _write_vt_data {
my $self = shift;
my $type = shift;
my $data = shift;
$self->xml_data_element( "vt:$type", $data );
}
###############################################################################
#
# _write_company()
#
# Write the <Company> element.
#
sub _write_company {
my $self = shift;
my $data = $self->{_properties}->{company} || '';
$self->xml_data_element( 'Company', $data );
}
###############################################################################
#
# _write_manager()
#
# Write the <Manager> element.
#
sub _write_manager {
my $self = shift;
my $data = $self->{_properties}->{manager};
return unless $data;
$self->xml_data_element( 'Manager', $data );
}
###############################################################################
#
# _write_links_up_to_date()
#
# Write the <LinksUpToDate> element.
#
sub _write_links_up_to_date {
my $self = shift;
my $data = 'false';
$self->xml_data_element( 'LinksUpToDate', $data );
}
###############################################################################
#
# _write_shared_doc()
#
# Write the <SharedDoc> element.
#
sub _write_shared_doc {
my $self = shift;
my $data = 'false';
$self->xml_data_element( 'SharedDoc', $data );
}
###############################################################################
#
# _write_hyperlink_base()
#
# Write the <HyperlinkBase> element.
#
sub _write_hyperlink_base {
my $self = shift;
my $data = $self->{_properties}->{hyperlink_base};
return unless $data;
$self->xml_data_element( 'HyperlinkBase', $data );
}
###############################################################################
#
# _write_hyperlinks_changed()
#
# Write the <HyperlinksChanged> element.
#
sub _write_hyperlinks_changed {
my $self = shift;
my $data = 'false';
$self->xml_data_element( 'HyperlinksChanged', $data );
}
###############################################################################
#
# _write_app_version()
#
# Write the <AppVersion> element.
#
sub _write_app_version {
my $self = shift;
my $data = '12.0000';
$self->xml_data_element( 'AppVersion', $data );
}
1;
__END__
=pod
=head1 NAME
App - A class for writing the Excel XLSX app.xml file.
=head1 SYNOPSIS
See the documentation for L<Excel::Writer::XLSX>.
=head1 DESCRIPTION
This module is used in conjunction with L<Excel::Writer::XLSX>.
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
(c) MM-MMXX, John McNamara.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
=head1 LICENSE
Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut

View File

@@ -0,0 +1,427 @@
package Excel::Writer::XLSX::Package::Comments;
###############################################################################
#
# Comments - A class for writing the Excel XLSX Comments files.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use warnings;
use Carp;
use Excel::Writer::XLSX::Package::XMLwriter;
use Excel::Writer::XLSX::Utility qw(xl_rowcol_to_cell);
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
our $VERSION = '1.07';
###############################################################################
#
# Public and private API methods.
#
###############################################################################
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my $class = shift;
my $fh = shift;
my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh );
$self->{_author_ids} = {};
bless $self, $class;
return $self;
}
###############################################################################
#
# _assemble_xml_file()
#
# Assemble and write the XML file.
#
sub _assemble_xml_file {
my $self = shift;
my $comments_data = shift;
$self->xml_declaration;
# Write the comments element.
$self->_write_comments();
# Write the authors element.
$self->_write_authors( $comments_data );
# Write the commentList element.
$self->_write_comment_list( $comments_data );
$self->xml_end_tag( 'comments' );
# Close the XML writer filehandle.
$self->xml_get_fh()->close();
}
###############################################################################
#
# Internal methods.
#
###############################################################################
###############################################################################
#
# XML writing methods.
#
###############################################################################
##############################################################################
#
# _write_comments()
#
# Write the <comments> element.
#
sub _write_comments {
my $self = shift;
my $xmlns = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';
my @attributes = ( 'xmlns' => $xmlns );
$self->xml_start_tag( 'comments', @attributes );
}
##############################################################################
#
# _write_authors()
#
# Write the <authors> element.
#
sub _write_authors {
my $self = shift;
my $comment_data = shift;
my $author_count = 0;
$self->xml_start_tag( 'authors' );
for my $comment ( @$comment_data ) {
my $author = $comment->[3];
if ( defined $author && !exists $self->{_author_ids}->{$author} ) {
# Store the author id.
$self->{_author_ids}->{$author} = $author_count++;
# Write the author element.
$self->_write_author( $author );
}
}
$self->xml_end_tag( 'authors' );
}
##############################################################################
#
# _write_author()
#
# Write the <author> element.
#
sub _write_author {
my $self = shift;
my $data = shift;
$self->xml_data_element( 'author', $data );
}
##############################################################################
#
# _write_comment_list()
#
# Write the <commentList> element.
#
sub _write_comment_list {
my $self = shift;
my $comment_data = shift;
$self->xml_start_tag( 'commentList' );
for my $comment ( @$comment_data ) {
my $row = $comment->[0];
my $col = $comment->[1];
my $text = $comment->[2];
my $author = $comment->[3];
my $font_name = $comment->[6];
my $font_size = $comment->[7];
my $font_family = $comment->[8];
# Look up the author id.
my $author_id = undef;
$author_id = $self->{_author_ids}->{$author} if defined $author;
# Write the comment element.
my $font = [ $font_name, $font_size, $font_family ];
$self->_write_comment( $row, $col, $text, $author_id, $font );
}
$self->xml_end_tag( 'commentList' );
}
##############################################################################
#
# _write_comment()
#
# Write the <comment> element.
#
sub _write_comment {
my $self = shift;
my $row = shift;
my $col = shift;
my $text = shift;
my $author_id = shift;
my $ref = xl_rowcol_to_cell( $row, $col );
my $font = shift;
my @attributes = ( 'ref' => $ref );
push @attributes, ( 'authorId' => $author_id ) if defined $author_id;
$self->xml_start_tag( 'comment', @attributes );
# Write the text element.
$self->_write_text( $text, $font );
$self->xml_end_tag( 'comment' );
}
##############################################################################
#
# _write_text()
#
# Write the <text> element.
#
sub _write_text {
my $self = shift;
my $text = shift;
my $font = shift;
$self->xml_start_tag( 'text' );
# Write the text r element.
$self->_write_text_r( $text, $font );
$self->xml_end_tag( 'text' );
}
##############################################################################
#
# _write_text_r()
#
# Write the <r> element.
#
sub _write_text_r {
my $self = shift;
my $text = shift;
my $font = shift;
$self->xml_start_tag( 'r' );
# Write the rPr element.
$self->_write_r_pr($font);
# Write the text r element.
$self->_write_text_t( $text );
$self->xml_end_tag( 'r' );
}
##############################################################################
#
# _write_text_t()
#
# Write the text <t> element.
#
sub _write_text_t {
my $self = shift;
my $text = shift;
my @attributes = ();
if ( $text =~ /^\s/ || $text =~ /\s$/ ) {
push @attributes, ( 'xml:space' => 'preserve' );
}
$self->xml_data_element( 't', $text, @attributes );
}
##############################################################################
#
# _write_r_pr()
#
# Write the <rPr> element.
#
sub _write_r_pr {
my $self = shift;
my $font = shift;
$self->xml_start_tag( 'rPr' );
# Write the sz element.
$self->_write_sz($font->[1]);
# Write the color element.
$self->_write_color();
# Write the rFont element.
$self->_write_r_font($font->[0]);
# Write the family element.
$self->_write_family($font->[2]);
$self->xml_end_tag( 'rPr' );
}
##############################################################################
#
# _write_sz()
#
# Write the <sz> element.
#
sub _write_sz {
my $self = shift;
my $val = shift;
my @attributes = ( 'val' => $val );
$self->xml_empty_tag( 'sz', @attributes );
}
##############################################################################
#
# _write_color()
#
# Write the <color> element.
#
sub _write_color {
my $self = shift;
my $indexed = 81;
my @attributes = ( 'indexed' => $indexed );
$self->xml_empty_tag( 'color', @attributes );
}
##############################################################################
#
# _write_r_font()
#
# Write the <rFont> element.
#
sub _write_r_font {
my $self = shift;
my $val = shift;
my @attributes = ( 'val' => $val );
$self->xml_empty_tag( 'rFont', @attributes );
}
##############################################################################
#
# _write_family()
#
# Write the <family> element.
#
sub _write_family {
my $self = shift;
my $val = shift;
my @attributes = ( 'val' => $val );
$self->xml_empty_tag( 'family', @attributes );
}
1;
__END__
=pod
=head1 NAME
Comments - A class for writing the Excel XLSX Comments files.
=head1 SYNOPSIS
See the documentation for L<Excel::Writer::XLSX>.
=head1 DESCRIPTION
This module is used in conjunction with L<Excel::Writer::XLSX>.
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
(c) MM-MMXX, John McNamara.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
=head1 LICENSE
Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut

View File

@@ -0,0 +1,487 @@
package Excel::Writer::XLSX::Package::ContentTypes;
###############################################################################
#
# Excel::Writer::XLSX::Package::ContentTypes - A class for writing the Excel
# XLS [Content_Types] file.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use warnings;
use Carp;
use Excel::Writer::XLSX::Package::XMLwriter;
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
our $VERSION = '1.07';
###############################################################################
#
# Package data.
#
###############################################################################
my $app_package = 'application/vnd.openxmlformats-package.';
my $app_document = 'application/vnd.openxmlformats-officedocument.';
our @defaults = (
[ 'rels', $app_package . 'relationships+xml' ],
[ 'xml', 'application/xml' ],
);
our @overrides = (
[ '/docProps/app.xml', $app_document . 'extended-properties+xml' ],
[ '/docProps/core.xml', $app_package . 'core-properties+xml' ],
[ '/xl/styles.xml', $app_document . 'spreadsheetml.styles+xml' ],
[ '/xl/theme/theme1.xml', $app_document . 'theme+xml' ],
[ '/xl/workbook.xml', $app_document . 'spreadsheetml.sheet.main+xml' ],
);
###############################################################################
#
# Public and private API methods.
#
###############################################################################
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my $class = shift;
my $fh = shift;
my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh );
$self->{_defaults} = [@defaults];
$self->{_overrides} = [@overrides];
bless $self, $class;
return $self;
}
###############################################################################
#
# _assemble_xml_file()
#
# Assemble and write the XML file.
#
sub _assemble_xml_file {
my $self = shift;
$self->xml_declaration;
$self->_write_types();
$self->_write_defaults();
$self->_write_overrides();
$self->xml_end_tag( 'Types' );
# Close the XML writer filehandle.
$self->xml_get_fh()->close();
}
###############################################################################
#
# _add_default()
#
# Add elements to the ContentTypes defaults.
#
sub _add_default {
my $self = shift;
my $part_name = shift;
my $content_type = shift;
push @{ $self->{_defaults} }, [ $part_name, $content_type ];
}
###############################################################################
#
# _add_override()
#
# Add elements to the ContentTypes overrides.
#
sub _add_override {
my $self = shift;
my $part_name = shift;
my $content_type = shift;
push @{ $self->{_overrides} }, [ $part_name, $content_type ];
}
###############################################################################
#
# _add_worksheet_name()
#
# Add the name of a worksheet to the ContentTypes overrides.
#
sub _add_worksheet_name {
my $self = shift;
my $worksheet_name = shift;
$worksheet_name = "/xl/worksheets/$worksheet_name.xml";
$self->_add_override( $worksheet_name,
$app_document . 'spreadsheetml.worksheet+xml' );
}
###############################################################################
#
# _add_chartsheet_name()
#
# Add the name of a chartsheet to the ContentTypes overrides.
#
sub _add_chartsheet_name {
my $self = shift;
my $chartsheet_name = shift;
$chartsheet_name = "/xl/chartsheets/$chartsheet_name.xml";
$self->_add_override( $chartsheet_name,
$app_document . 'spreadsheetml.chartsheet+xml' );
}
###############################################################################
#
# _add_chart_name()
#
# Add the name of a chart to the ContentTypes overrides.
#
sub _add_chart_name {
my $self = shift;
my $chart_name = shift;
$chart_name = "/xl/charts/$chart_name.xml";
$self->_add_override( $chart_name, $app_document . 'drawingml.chart+xml' );
}
###############################################################################
#
# _add_drawing_name()
#
# Add the name of a drawing to the ContentTypes overrides.
#
sub _add_drawing_name {
my $self = shift;
my $drawing_name = shift;
$drawing_name = "/xl/drawings/$drawing_name.xml";
$self->_add_override( $drawing_name, $app_document . 'drawing+xml' );
}
###############################################################################
#
# _add_vml_name()
#
# Add the name of a VML drawing to the ContentTypes defaults.
#
sub _add_vml_name {
my $self = shift;
$self->_add_default( 'vml', $app_document . 'vmlDrawing' );
}
###############################################################################
#
# _add_comment_name()
#
# Add the name of a comment to the ContentTypes overrides.
#
sub _add_comment_name {
my $self = shift;
my $comment_name = shift;
$comment_name = "/xl/$comment_name.xml";
$self->_add_override( $comment_name,
$app_document . 'spreadsheetml.comments+xml' );
}
###############################################################################
#
# _Add_shared_strings()
#
# Add the sharedStrings link to the ContentTypes overrides.
#
sub _add_shared_strings {
my $self = shift;
$self->_add_override( '/xl/sharedStrings.xml',
$app_document . 'spreadsheetml.sharedStrings+xml' );
}
###############################################################################
#
# _add_calc_chain()
#
# Add the calcChain link to the ContentTypes overrides.
#
sub _add_calc_chain {
my $self = shift;
$self->_add_override( '/xl/calcChain.xml',
$app_document . 'spreadsheetml.calcChain+xml' );
}
###############################################################################
#
# _add_image_types()
#
# Add the image default types.
#
sub _add_image_types {
my $self = shift;
my %types = @_;
for my $type ( keys %types ) {
$self->_add_default( $type, 'image/' . $type );
}
}
###############################################################################
#
# _add_table_name()
#
# Add the name of a table to the ContentTypes overrides.
#
sub _add_table_name {
my $self = shift;
my $table_name = shift;
$table_name = "/xl/tables/$table_name.xml";
$self->_add_override( $table_name,
$app_document . 'spreadsheetml.table+xml' );
}
###############################################################################
#
# _add_vba_project()
#
# Add a vbaProject to the ContentTypes defaults.
#
sub _add_vba_project {
my $self = shift;
# Change the workbook.xml content-type from xlsx to xlsm.
for my $aref ( @{ $self->{_overrides} } ) {
if ( $aref->[0] eq '/xl/workbook.xml' ) {
$aref->[1] = 'application/vnd.ms-excel.sheet.macroEnabled.main+xml';
}
}
$self->_add_default( 'bin', 'application/vnd.ms-office.vbaProject' );
}
###############################################################################
#
# _add_custom_properties()
#
# Add the custom properties to the ContentTypes overrides.
#
sub _add_custom_properties {
my $self = shift;
my $custom = "/docProps/custom.xml";
$self->_add_override( $custom, $app_document . 'custom-properties+xml' );
}
###############################################################################
#
# Internal methods.
#
###############################################################################
###############################################################################
#
# _write_defaults()
#
# Write out all of the <Default> types.
#
sub _write_defaults {
my $self = shift;
for my $aref ( @{ $self->{_defaults} } ) {
#<<<
$self->xml_empty_tag(
'Default',
'Extension', $aref->[0],
'ContentType', $aref->[1] );
#>>>
}
}
###############################################################################
#
# _write_overrides()
#
# Write out all of the <Override> types.
#
sub _write_overrides {
my $self = shift;
for my $aref ( @{ $self->{_overrides} } ) {
#<<<
$self->xml_empty_tag(
'Override',
'PartName', $aref->[0],
'ContentType', $aref->[1] );
#>>>
}
}
###############################################################################
#
# XML writing methods.
#
###############################################################################
###############################################################################
#
# _write_types()
#
# Write the <Types> element.
#
sub _write_types {
my $self = shift;
my $xmlns = 'http://schemas.openxmlformats.org/package/2006/content-types';
my @attributes = ( 'xmlns' => $xmlns, );
$self->xml_start_tag( 'Types', @attributes );
}
###############################################################################
#
# _write_default()
#
# Write the <Default> element.
#
sub _write_default {
my $self = shift;
my $extension = shift;
my $content_type = shift;
my @attributes = (
'Extension' => $extension,
'ContentType' => $content_type,
);
$self->xml_empty_tag( 'Default', @attributes );
}
###############################################################################
#
# _write_override()
#
# Write the <Override> element.
#
sub _write_override {
my $self = shift;
my $part_name = shift;
my $content_type = shift;
my $writer = $self;
my @attributes = (
'PartName' => $part_name,
'ContentType' => $content_type,
);
$self->xml_empty_tag( 'Override', @attributes );
}
1;
__END__
=pod
=head1 NAME
Excel::Writer::XLSX::Package::ContentTypes - A class for writing the Excel XLSX [Content_Types] file.
=head1 SYNOPSIS
See the documentation for L<Excel::Writer::XLSX>.
=head1 DESCRIPTION
This module is used in conjunction with L<Excel::Writer::XLSX>.
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
(c) MM-MMXX, John McNamara.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
=head1 LICENSE
Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut

View File

@@ -0,0 +1,372 @@
package Excel::Writer::XLSX::Package::Core;
###############################################################################
#
# Core - A class for writing the Excel XLSX core.xml file.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use warnings;
use Carp;
use Excel::Writer::XLSX::Package::XMLwriter;
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
our $VERSION = '1.07';
###############################################################################
#
# Public and private API methods.
#
###############################################################################
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my $class = shift;
my $fh = shift;
my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh );
$self->{_properties} = {};
$self->{_createtime} = [ gmtime() ];
bless $self, $class;
return $self;
}
###############################################################################
#
# _assemble_xml_file()
#
# Assemble and write the XML file.
#
sub _assemble_xml_file {
my $self = shift;
$self->xml_declaration;
$self->_write_cp_core_properties();
$self->_write_dc_title();
$self->_write_dc_subject();
$self->_write_dc_creator();
$self->_write_cp_keywords();
$self->_write_dc_description();
$self->_write_cp_last_modified_by();
$self->_write_dcterms_created();
$self->_write_dcterms_modified();
$self->_write_cp_category();
$self->_write_cp_content_status();
$self->xml_end_tag( 'cp:coreProperties' );
# Close the XML writer filehandle.
$self->xml_get_fh()->close();
}
###############################################################################
#
# _set_properties()
#
# Set the document properties.
#
sub _set_properties {
my $self = shift;
my $properties = shift;
$self->{_properties} = $properties;
}
###############################################################################
#
# Internal methods.
#
###############################################################################
###############################################################################
#
# _datetime_to_iso8601_date()
#
# Convert a gmtime/localtime() date to a ISO 8601 style "2010-01-01T00:00:00Z"
# date. Excel always treats this as a utc date/time.
#
sub _datetime_to_iso8601_date {
my $self = shift;
my $gmtime = shift || $self->{_createtime};
my ( $seconds, $minutes, $hours, $day, $month, $year ) = @$gmtime;
$month++;
$year += 1900;
my $date = sprintf "%4d-%02d-%02dT%02d:%02d:%02dZ", $year, $month, $day,
$hours, $minutes, $seconds;
}
###############################################################################
#
# XML writing methods.
#
###############################################################################
###############################################################################
#
# _write_cp_core_properties()
#
# Write the <cp:coreProperties> element.
#
sub _write_cp_core_properties {
my $self = shift;
my $xmlns_cp =
'http://schemas.openxmlformats.org/package/2006/metadata/core-properties';
my $xmlns_dc = 'http://purl.org/dc/elements/1.1/';
my $xmlns_dcterms = 'http://purl.org/dc/terms/';
my $xmlns_dcmitype = 'http://purl.org/dc/dcmitype/';
my $xmlns_xsi = 'http://www.w3.org/2001/XMLSchema-instance';
my @attributes = (
'xmlns:cp' => $xmlns_cp,
'xmlns:dc' => $xmlns_dc,
'xmlns:dcterms' => $xmlns_dcterms,
'xmlns:dcmitype' => $xmlns_dcmitype,
'xmlns:xsi' => $xmlns_xsi,
);
$self->xml_start_tag( 'cp:coreProperties', @attributes );
}
###############################################################################
#
# _write_dc_creator()
#
# Write the <dc:creator> element.
#
sub _write_dc_creator {
my $self = shift;
my $data = $self->{_properties}->{author} || '';
$self->xml_data_element( 'dc:creator', $data );
}
###############################################################################
#
# _write_cp_last_modified_by()
#
# Write the <cp:lastModifiedBy> element.
#
sub _write_cp_last_modified_by {
my $self = shift;
my $data = $self->{_properties}->{author} || '';
$self->xml_data_element( 'cp:lastModifiedBy', $data );
}
###############################################################################
#
# _write_dcterms_created()
#
# Write the <dcterms:created> element.
#
sub _write_dcterms_created {
my $self = shift;
my $date = $self->{_properties}->{created};
my $xsi_type = 'dcterms:W3CDTF';
$date = $self->_datetime_to_iso8601_date( $date );
my @attributes = ( 'xsi:type' => $xsi_type, );
$self->xml_data_element( 'dcterms:created', $date, @attributes );
}
###############################################################################
#
# _write_dcterms_modified()
#
# Write the <dcterms:modified> element.
#
sub _write_dcterms_modified {
my $self = shift;
my $date = $self->{_properties}->{created};
my $xsi_type = 'dcterms:W3CDTF';
$date = $self->_datetime_to_iso8601_date( $date );
my @attributes = ( 'xsi:type' => $xsi_type, );
$self->xml_data_element( 'dcterms:modified', $date, @attributes );
}
##############################################################################
#
# _write_dc_title()
#
# Write the <dc:title> element.
#
sub _write_dc_title {
my $self = shift;
my $data = $self->{_properties}->{title};
return unless $data;
$self->xml_data_element( 'dc:title', $data );
}
##############################################################################
#
# _write_dc_subject()
#
# Write the <dc:subject> element.
#
sub _write_dc_subject {
my $self = shift;
my $data = $self->{_properties}->{subject};
return unless $data;
$self->xml_data_element( 'dc:subject', $data );
}
##############################################################################
#
# _write_cp_keywords()
#
# Write the <cp:keywords> element.
#
sub _write_cp_keywords {
my $self = shift;
my $data = $self->{_properties}->{keywords};
return unless $data;
$self->xml_data_element( 'cp:keywords', $data );
}
##############################################################################
#
# _write_dc_description()
#
# Write the <dc:description> element.
#
sub _write_dc_description {
my $self = shift;
my $data = $self->{_properties}->{comments};
return unless $data;
$self->xml_data_element( 'dc:description', $data );
}
##############################################################################
#
# _write_cp_category()
#
# Write the <cp:category> element.
#
sub _write_cp_category {
my $self = shift;
my $data = $self->{_properties}->{category};
return unless $data;
$self->xml_data_element( 'cp:category', $data );
}
##############################################################################
#
# _write_cp_content_status()
#
# Write the <cp:contentStatus> element.
#
sub _write_cp_content_status {
my $self = shift;
my $data = $self->{_properties}->{status};
return unless $data;
$self->xml_data_element( 'cp:contentStatus', $data );
}
1;
__END__
=pod
=head1 NAME
Core - A class for writing the Excel XLSX core.xml file.
=head1 SYNOPSIS
See the documentation for L<Excel::Writer::XLSX>.
=head1 DESCRIPTION
This module is used in conjunction with L<Excel::Writer::XLSX>.
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
(c) MM-MMXX, John McNamara.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
=head1 LICENSE
Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut

View File

@@ -0,0 +1,306 @@
package Excel::Writer::XLSX::Package::Custom;
###############################################################################
#
# Custom - A class for writing the Excel XLSX custom.xml file for custom
# workbook properties.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use warnings;
use Carp;
use Excel::Writer::XLSX::Package::XMLwriter;
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
our $VERSION = '1.07';
###############################################################################
#
# Public and private API methods.
#
###############################################################################
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my $class = shift;
my $fh = shift;
my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh );
$self->{_properties} = [];
$self->{_pid} = 1;
bless $self, $class;
return $self;
}
###############################################################################
#
# _assemble_xml_file()
#
# Assemble and write the XML file.
#
sub _assemble_xml_file {
my $self = shift;
$self->xml_declaration;
$self->_write_properties();
$self->xml_end_tag( 'Properties' );
# Close the XML writer filehandle.
$self->xml_get_fh()->close();
}
###############################################################################
#
# _set_properties()
#
# Set the document properties.
#
sub _set_properties {
my $self = shift;
my $properties = shift;
$self->{_properties} = $properties;
}
###############################################################################
#
# Internal methods.
#
###############################################################################
###############################################################################
#
# XML writing methods.
#
###############################################################################
###############################################################################
#
# _write_properties()
#
# Write the <Properties> element.
#
sub _write_properties {
my $self = shift;
my $schema = 'http://schemas.openxmlformats.org/officeDocument/2006/';
my $xmlns = $schema . 'custom-properties';
my $xmlns_vt = $schema . 'docPropsVTypes';
my @attributes = (
'xmlns' => $xmlns,
'xmlns:vt' => $xmlns_vt,
);
$self->xml_start_tag( 'Properties', @attributes );
for my $property ( @{ $self->{_properties} } ) {
# Write the property element.
$self->_write_property( $property );
}
}
##############################################################################
#
# _write_property()
#
# Write the <property> element.
#
sub _write_property {
my $self = shift;
my $property = shift;
my $fmtid = '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}';
$self->{_pid}++;
my ( $name, $value, $type ) = @$property;
my @attributes = (
'fmtid' => $fmtid,
'pid' => $self->{_pid},
'name' => $name,
);
$self->xml_start_tag( 'property', @attributes );
if ( $type eq 'date' ) {
# Write the vt:filetime element.
$self->_write_vt_filetime( $value );
}
elsif ( $type eq 'number' ) {
# Write the vt:r8 element.
$self->_write_vt_r8( $value );
}
elsif ( $type eq 'number_int' ) {
# Write the vt:i4 element.
$self->_write_vt_i4( $value );
}
elsif ( $type eq 'bool' ) {
# Write the vt:bool element.
$self->_write_vt_bool( $value );
}
else {
# Write the vt:lpwstr element.
$self->_write_vt_lpwstr( $value );
}
$self->xml_end_tag( 'property' );
}
##############################################################################
#
# _write_vt_lpwstr()
#
# Write the <vt:lpwstr> element.
#
sub _write_vt_lpwstr {
my $self = shift;
my $data = shift;
$self->xml_data_element( 'vt:lpwstr', $data );
}
##############################################################################
#
# _write_vt_i4()
#
# Write the <vt:i4> element.
#
sub _write_vt_i4 {
my $self = shift;
my $data = shift;
$self->xml_data_element( 'vt:i4', $data );
}
##############################################################################
#
# _write_vt_r8()
#
# Write the <vt:r8> element.
#
sub _write_vt_r8 {
my $self = shift;
my $data = shift;
$self->xml_data_element( 'vt:r8', $data );
}
##############################################################################
#
# _write_vt_bool()
#
# Write the <vt:bool> element.
#
sub _write_vt_bool {
my $self = shift;
my $data = shift;
if ( $data ) {
$data = 'true';
}
else {
$data = 'false';
}
$self->xml_data_element( 'vt:bool', $data );
}
##############################################################################
#
# _write_vt_filetime()
#
# Write the <vt:filetime> element.
#
sub _write_vt_filetime {
my $self = shift;
my $data = shift;
$self->xml_data_element( 'vt:filetime', $data );
}
1;
__END__
=pod
=head1 NAME
Custom - A class for writing the Excel XLSX custom.xml file.
=head1 SYNOPSIS
See the documentation for L<Excel::Writer::XLSX>.
=head1 DESCRIPTION
This module is used in conjunction with L<Excel::Writer::XLSX>.
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
(c) MM-MMXX, John McNamara.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
=head1 LICENSE
Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,248 @@
package Excel::Writer::XLSX::Package::Relationships;
###############################################################################
#
# Relationships - A class for writing the Excel XLSX Rels file.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use warnings;
use Carp;
use Excel::Writer::XLSX::Package::XMLwriter;
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
our $VERSION = '1.07';
our $schema_root = 'http://schemas.openxmlformats.org';
our $package_schema = $schema_root . '/package/2006/relationships';
our $document_schema = $schema_root . '/officeDocument/2006/relationships';
###############################################################################
#
# Public and private API methods.
#
###############################################################################
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my $class = shift;
my $fh = shift;
my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh );
$self->{_rels} = [];
$self->{_id} = 1;
bless $self, $class;
return $self;
}
###############################################################################
#
# _assemble_xml_file()
#
# Assemble and write the XML file.
#
sub _assemble_xml_file {
my $self = shift;
$self->xml_declaration;
$self->_write_relationships();
}
###############################################################################
#
# _add_document_relationship()
#
# Add container relationship to XLSX .rels xml files.
#
sub _add_document_relationship {
my $self = shift;
my $type = shift;
my $target = shift;
my $target_mode = shift;
$type = $document_schema . $type;
push @{ $self->{_rels} }, [ $type, $target, $target_mode ];
}
###############################################################################
#
# _add_package_relationship()
#
# Add container relationship to XLSX .rels xml files.
#
sub _add_package_relationship {
my $self = shift;
my $type = shift;
my $target = shift;
$type = $package_schema . $type;
push @{ $self->{_rels} }, [ $type, $target ];
}
###############################################################################
#
# _add_ms_package_relationship()
#
# Add container relationship to XLSX .rels xml files. Uses MS schema.
#
sub _add_ms_package_relationship {
my $self = shift;
my $type = shift;
my $target = shift;
my $schema = 'http://schemas.microsoft.com/office/2006/relationships';
$type = $schema . $type;
push @{ $self->{_rels} }, [ $type, $target ];
}
###############################################################################
#
# _add_worksheet_relationship()
#
# Add worksheet relationship to sheet.rels xml files.
#
sub _add_worksheet_relationship {
my $self = shift;
my $type = shift;
my $target = shift;
my $target_mode = shift;
$type = $document_schema . $type;
push @{ $self->{_rels} }, [ $type, $target, $target_mode ];
}
###############################################################################
#
# Internal methods.
#
###############################################################################
###############################################################################
#
# XML writing methods.
#
###############################################################################
##############################################################################
#
# _write_relationships()
#
# Write the <Relationships> element.
#
sub _write_relationships {
my $self = shift;
my @attributes = ( 'xmlns' => $package_schema, );
$self->xml_start_tag( 'Relationships', @attributes );
for my $rel ( @{ $self->{_rels} } ) {
$self->_write_relationship( @$rel );
}
$self->xml_end_tag( 'Relationships' );
# Close the XML writer filehandle.
$self->xml_get_fh()->close();
}
##############################################################################
#
# _write_relationship()
#
# Write the <Relationship> element.
#
sub _write_relationship {
my $self = shift;
my $type = shift;
my $target = shift;
my $target_mode = shift;
my @attributes = (
'Id' => 'rId' . $self->{_id}++,
'Type' => $type,
'Target' => $target,
);
push @attributes, ( 'TargetMode' => $target_mode ) if $target_mode;
$self->xml_empty_tag( 'Relationship', @attributes );
}
1;
__END__
=pod
=head1 NAME
Relationships - A class for writing the Excel XLSX Rels file.
=head1 SYNOPSIS
See the documentation for L<Excel::Writer::XLSX>.
=head1 DESCRIPTION
This module is used in conjunction with L<Excel::Writer::XLSX>.
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
(c) MM-MMXX, John McNamara.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
=head1 LICENSE
Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut

View File

@@ -0,0 +1,260 @@
package Excel::Writer::XLSX::Package::SharedStrings;
###############################################################################
#
# SharedStrings - A class for writing the Excel XLSX sharedStrings file.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use warnings;
use Carp;
use Encode;
use Excel::Writer::XLSX::Package::XMLwriter;
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
our $VERSION = '1.07';
###############################################################################
#
# Public and private API methods.
#
###############################################################################
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my $class = shift;
my $fh = shift;
my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh );
$self->{_strings} = [];
$self->{_string_count} = 0;
$self->{_unique_count} = 0;
bless $self, $class;
return $self;
}
###############################################################################
#
# _assemble_xml_file()
#
# Assemble and write the XML file.
#
sub _assemble_xml_file {
my $self = shift;
$self->xml_declaration;
# Write the sst table.
$self->_write_sst( $self->{_string_count}, $self->{_unique_count} );
# Write the sst strings.
$self->_write_sst_strings();
# Close the sst tag.
$self->xml_end_tag( 'sst' );
# Close the XML writer filehandle.
$self->xml_get_fh()->close();
}
###############################################################################
#
# _set_string_count()
#
# Set the total sst string count.
#
sub _set_string_count {
my $self = shift;
$self->{_string_count} = shift;
}
###############################################################################
#
# _set_unique_count()
#
# Set the total of unique sst strings.
#
sub _set_unique_count {
my $self = shift;
$self->{_unique_count} = shift;
}
###############################################################################
#
# _add_strings()
#
# Add the array ref of strings to be written.
#
sub _add_strings {
my $self = shift;
$self->{_strings} = shift;
}
###############################################################################
#
# Internal methods.
#
###############################################################################
###############################################################################
#
# XML writing methods.
#
###############################################################################
##############################################################################
#
# _write_sst()
#
# Write the <sst> element.
#
sub _write_sst {
my $self = shift;
my $count = shift;
my $unique_count = shift;
my $schema = 'http://schemas.openxmlformats.org';
my $xmlns = $schema . '/spreadsheetml/2006/main';
my @attributes = (
'xmlns' => $xmlns,
'count' => $count,
'uniqueCount' => $unique_count,
);
$self->xml_start_tag( 'sst', @attributes );
}
###############################################################################
#
# _write_sst_strings()
#
# Write the sst string elements.
#
sub _write_sst_strings {
my $self = shift;
for my $string ( @{ $self->{_strings} } ) {
$self->_write_si( $string );
}
}
##############################################################################
#
# _write_si()
#
# Write the <si> element.
#
sub _write_si {
my $self = shift;
my $string = shift;
my @attributes = ();
# Excel escapes control characters with _xHHHH_ and also escapes any
# literal strings of that type by encoding the leading underscore. So
# "\0" -> _x0000_ and "_x0000_" -> _x005F_x0000_.
# The following substitutions deal with those cases.
# Escape the escape.
$string =~ s/(_x[0-9a-fA-F]{4}_)/_x005F$1/g;
# Convert control character to the _xHHHH_ escape.
$string =~ s/([\x00-\x08\x0B-\x1F])/sprintf "_x%04X_", ord($1)/eg;
# Add attribute to preserve leading or trailing whitespace.
if ( $string =~ /^\s/ || $string =~ /\s$/ ) {
push @attributes, ( 'xml:space' => 'preserve' );
}
# Write any rich strings without further tags.
if ( $string =~ m{^<r>} && $string =~ m{</r>$} ) {
# Prevent utf8 strings from getting double encoded.
$string = decode_utf8( $string );
$self->xml_rich_si_element( $string );
}
else {
$self->xml_si_element( $string, @attributes );
}
}
1;
__END__
=pod
=head1 NAME
SharedStrings - A class for writing the Excel XLSX sharedStrings.xml file.
=head1 SYNOPSIS
See the documentation for L<Excel::Writer::XLSX>.
=head1 DESCRIPTION
This module is used in conjunction with L<Excel::Writer::XLSX>.
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
(c) MM-MMXX, John McNamara.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
=head1 LICENSE
Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,328 @@
package Excel::Writer::XLSX::Package::Table;
###############################################################################
#
# Table - A class for writing the Excel XLSX Table file.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use warnings;
use Carp;
use Excel::Writer::XLSX::Package::XMLwriter;
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
our $VERSION = '1.07';
###############################################################################
#
# Public and private API methods.
#
###############################################################################
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my $class = shift;
my $fh = shift;
my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh );
$self->{_properties} = {};
bless $self, $class;
return $self;
}
###############################################################################
#
# _assemble_xml_file()
#
# Assemble and write the XML file.
#
sub _assemble_xml_file {
my $self = shift;
$self->xml_declaration;
# Write the table element.
$self->_write_table();
# Write the autoFilter element.
$self->_write_auto_filter();
# Write the tableColumns element.
$self->_write_table_columns();
# Write the tableStyleInfo element.
$self->_write_table_style_info();
# Close the table tag.
$self->xml_end_tag( 'table' );
# Close the XML writer filehandle.
$self->xml_get_fh()->close();
}
###############################################################################
#
# _set_properties()
#
# Set the document properties.
#
sub _set_properties {
my $self = shift;
my $properties = shift;
$self->{_properties} = $properties;
}
###############################################################################
#
# Internal methods.
#
###############################################################################
###############################################################################
#
# XML writing methods.
#
###############################################################################
##############################################################################
#
# _write_table()
#
# Write the <table> element.
#
sub _write_table {
my $self = shift;
my $schema = 'http://schemas.openxmlformats.org/';
my $xmlns = $schema . 'spreadsheetml/2006/main';
my $id = $self->{_properties}->{_id};
my $name = $self->{_properties}->{_name};
my $display_name = $self->{_properties}->{_name};
my $ref = $self->{_properties}->{_range};
my $totals_row_shown = $self->{_properties}->{_totals_row_shown};
my $header_row_count = $self->{_properties}->{_header_row_count};
my @attributes = (
'xmlns' => $xmlns,
'id' => $id,
'name' => $name,
'displayName' => $display_name,
'ref' => $ref,
);
push @attributes, ( 'headerRowCount' => 0 ) if !$header_row_count;
if ( $totals_row_shown ) {
push @attributes, ( 'totalsRowCount' => 1 );
}
else {
push @attributes, ( 'totalsRowShown' => 0 );
}
$self->xml_start_tag( 'table', @attributes );
}
##############################################################################
#
# _write_auto_filter()
#
# Write the <autoFilter> element.
#
sub _write_auto_filter {
my $self = shift;
my $autofilter = $self->{_properties}->{_autofilter};
return unless $autofilter;
my @attributes = ( 'ref' => $autofilter, );
$self->xml_empty_tag( 'autoFilter', @attributes );
}
##############################################################################
#
# _write_table_columns()
#
# Write the <tableColumns> element.
#
sub _write_table_columns {
my $self = shift;
my @columns = @{ $self->{_properties}->{_columns} };
my $count = scalar @columns;
my @attributes = ( 'count' => $count, );
$self->xml_start_tag( 'tableColumns', @attributes );
for my $col_data ( @columns ) {
# Write the tableColumn element.
$self->_write_table_column( $col_data );
}
$self->xml_end_tag( 'tableColumns' );
}
##############################################################################
#
# _write_table_column()
#
# Write the <tableColumn> element.
#
sub _write_table_column {
my $self = shift;
my $col_data = shift;
my @attributes = (
'id' => $col_data->{_id},
'name' => $col_data->{_name},
);
if ( $col_data->{_total_string} ) {
push @attributes, ( totalsRowLabel => $col_data->{_total_string} );
}
elsif ( $col_data->{_total_function} ) {
push @attributes, ( totalsRowFunction => $col_data->{_total_function} );
}
if ( defined $col_data->{_format} ) {
push @attributes, ( dataDxfId => $col_data->{_format} );
}
if ( $col_data->{_formula} ) {
$self->xml_start_tag( 'tableColumn', @attributes );
# Write the calculatedColumnFormula element.
$self->_write_calculated_column_formula( $col_data->{_formula} );
$self->xml_end_tag( 'tableColumn' );
}
else {
$self->xml_empty_tag( 'tableColumn', @attributes );
}
}
##############################################################################
#
# _write_table_style_info()
#
# Write the <tableStyleInfo> element.
#
sub _write_table_style_info {
my $self = shift;
my $props = $self->{_properties};
my @attributes = ();
my $name = $props->{_style};
my $show_first_column = $props->{_show_first_col};
my $show_last_column = $props->{_show_last_col};
my $show_row_stripes = $props->{_show_row_stripes};
my $show_column_stripes = $props->{_show_col_stripes};
if ( $name && $name ne '' && $name ne 'None' ) {
push @attributes, ( 'name' => $name );
}
push @attributes, ( 'showFirstColumn' => $show_first_column );
push @attributes, ( 'showLastColumn' => $show_last_column );
push @attributes, ( 'showRowStripes' => $show_row_stripes );
push @attributes, ( 'showColumnStripes' => $show_column_stripes );
$self->xml_empty_tag( 'tableStyleInfo', @attributes );
}
##############################################################################
#
# _write_calculated_column_formula()
#
# Write the <calculatedColumnFormula> element.
#
sub _write_calculated_column_formula {
my $self = shift;
my $formula = shift;
$self->xml_data_element( 'calculatedColumnFormula', $formula );
}
1;
__END__
=pod
=head1 NAME
Table - A class for writing the Excel XLSX Table file.
=head1 SYNOPSIS
See the documentation for L<Excel::Writer::XLSX>.
=head1 DESCRIPTION
This module is used in conjunction with L<Excel::Writer::XLSX>.
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
(c) MM-MMXX, John McNamara.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
=head1 LICENSE
Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,534 @@
package Excel::Writer::XLSX::Package::XMLwriter;
###############################################################################
#
# XMLwriter - A base class for the Excel::Writer::XLSX writer classes.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use warnings;
use Exporter;
use Carp;
use IO::File;
our @ISA = qw(Exporter);
our $VERSION = '1.07';
#
# NOTE: this module is a light weight re-implementation of XML::Writer. See
# the Pod docs below for a full explanation. The methods are implemented
# for speed rather than readability since they are used heavily in tight
# loops by Excel::Writer::XLSX.
#
# Note "local $\ = undef" protect print statements from -l on commandline.
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my $class = shift;
# FH may be undef and set later in _set_xml_writer(), see below.
my $fh = shift;
my $self = { _fh => $fh };
bless $self, $class;
return $self;
}
###############################################################################
#
# _set_xml_writer()
#
# Set the XML writer filehandle for the object. This can either be done
# in the constructor (usually for testing since the file name isn't generally
# known at that stage) or later via this method.
#
sub _set_xml_writer {
my $self = shift;
my $filename = shift;
my $fh = IO::File->new( $filename, 'w' );
croak "Couldn't open file $filename for writing.\n" unless $fh;
binmode $fh, ':utf8';
$self->{_fh} = $fh;
}
###############################################################################
#
# xml_declaration()
#
# Write the XML declaration.
#
sub xml_declaration {
my $self = shift;
local $\ = undef;
print { $self->{_fh} }
qq(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n);
}
###############################################################################
#
# xml_start_tag()
#
# Write an XML start tag with optional attributes.
#
sub xml_start_tag {
my $self = shift;
my $tag = shift;
while ( @_ ) {
my $key = shift @_;
my $value = shift @_;
$value = _escape_attributes( $value );
$tag .= qq( $key="$value");
}
local $\ = undef;
print { $self->{_fh} } "<$tag>";
}
###############################################################################
#
# xml_start_tag_unencoded()
#
# Write an XML start tag with optional, unencoded, attributes.
# This is a minor speed optimisation for elements that don't need encoding.
#
sub xml_start_tag_unencoded {
my $self = shift;
my $tag = shift;
while ( @_ ) {
my $key = shift @_;
my $value = shift @_;
$tag .= qq( $key="$value");
}
local $\ = undef;
print { $self->{_fh} } "<$tag>";
}
###############################################################################
#
# xml_end_tag()
#
# Write an XML end tag.
#
sub xml_end_tag {
my $self = shift;
my $tag = shift;
local $\ = undef;
print { $self->{_fh} } "</$tag>";
}
###############################################################################
#
# xml_empty_tag()
#
# Write an empty XML tag with optional attributes.
#
sub xml_empty_tag {
my $self = shift;
my $tag = shift;
while ( @_ ) {
my $key = shift @_;
my $value = shift @_;
$value = _escape_attributes( $value );
$tag .= qq( $key="$value");
}
local $\ = undef;
print { $self->{_fh} } "<$tag/>";
}
###############################################################################
#
# xml_empty_tag_unencoded()
#
# Write an empty XML tag with optional, unencoded, attributes.
# This is a minor speed optimisation for elements that don't need encoding.
#
sub xml_empty_tag_unencoded {
my $self = shift;
my $tag = shift;
while ( @_ ) {
my $key = shift @_;
my $value = shift @_;
$tag .= qq( $key="$value");
}
local $\ = undef;
print { $self->{_fh} } "<$tag/>";
}
###############################################################################
#
# xml_data_element()
#
# Write an XML element containing data with optional attributes.
# XML characters in the data are encoded.
#
sub xml_data_element {
my $self = shift;
my $tag = shift;
my $data = shift;
my $end_tag = $tag;
while ( @_ ) {
my $key = shift @_;
my $value = shift @_;
$value = _escape_attributes( $value );
$tag .= qq( $key="$value");
}
$data = _escape_data( $data );
local $\ = undef;
print { $self->{_fh} } "<$tag>$data</$end_tag>";
}
###############################################################################
#
# xml_data_element_unencoded()
#
# Write an XML unencoded element containing data with optional attributes.
# This is a minor speed optimisation for elements that don't need encoding.
#
sub xml_data_element_unencoded {
my $self = shift;
my $tag = shift;
my $data = shift;
my $end_tag = $tag;
while ( @_ ) {
my $key = shift @_;
my $value = shift @_;
$tag .= qq( $key="$value");
}
local $\ = undef;
print { $self->{_fh} } "<$tag>$data</$end_tag>";
}
###############################################################################
#
# xml_string_element()
#
# Optimised tag writer for <c> cell string elements in the inner loop.
#
sub xml_string_element {
my $self = shift;
my $index = shift;
my $attr = '';
while ( @_ ) {
my $key = shift;
my $value = shift;
$attr .= qq( $key="$value");
}
local $\ = undef;
print { $self->{_fh} } "<c$attr t=\"s\"><v>$index</v></c>";
}
###############################################################################
#
# xml_si_element()
#
# Optimised tag writer for shared strings <si> elements.
#
sub xml_si_element {
my $self = shift;
my $string = shift;
my $attr = '';
while ( @_ ) {
my $key = shift;
my $value = shift;
$attr .= qq( $key="$value");
}
$string = _escape_data( $string );
local $\ = undef;
print { $self->{_fh} } "<si><t$attr>$string</t></si>";
}
###############################################################################
#
# xml_rich_si_element()
#
# Optimised tag writer for shared strings <si> rich string elements.
#
sub xml_rich_si_element {
my $self = shift;
my $string = shift;
local $\ = undef;
print { $self->{_fh} } "<si>$string</si>";
}
###############################################################################
#
# xml_number_element()
#
# Optimised tag writer for <c> cell number elements in the inner loop.
#
sub xml_number_element {
my $self = shift;
my $number = shift;
my $attr = '';
while ( @_ ) {
my $key = shift;
my $value = shift;
$attr .= qq( $key="$value");
}
local $\ = undef;
print { $self->{_fh} } "<c$attr><v>$number</v></c>";
}
###############################################################################
#
# xml_formula_element()
#
# Optimised tag writer for <c> cell formula elements in the inner loop.
#
sub xml_formula_element {
my $self = shift;
my $formula = shift;
my $result = shift;
my $attr = '';
while ( @_ ) {
my $key = shift;
my $value = shift;
$attr .= qq( $key="$value");
}
$formula = _escape_data( $formula );
local $\ = undef;
print { $self->{_fh} } "<c$attr><f>$formula</f><v>$result</v></c>";
}
###############################################################################
#
# xml_inline_string()
#
# Optimised tag writer for inlineStr cell elements in the inner loop.
#
sub xml_inline_string {
my $self = shift;
my $string = shift;
my $preserve = shift;
my $attr = '';
my $t_attr = '';
# Set the <t> attribute to preserve whitespace.
$t_attr = ' xml:space="preserve"' if $preserve;
while ( @_ ) {
my $key = shift;
my $value = shift;
$attr .= qq( $key="$value");
}
$string = _escape_data( $string );
local $\ = undef;
print { $self->{_fh} }
"<c$attr t=\"inlineStr\"><is><t$t_attr>$string</t></is></c>";
}
###############################################################################
#
# xml_rich_inline_string()
#
# Optimised tag writer for rich inlineStr cell elements in the inner loop.
#
sub xml_rich_inline_string {
my $self = shift;
my $string = shift;
my $attr = '';
while ( @_ ) {
my $key = shift;
my $value = shift;
$attr .= qq( $key="$value");
}
local $\ = undef;
print { $self->{_fh} } "<c$attr t=\"inlineStr\"><is>$string</is></c>";
}
###############################################################################
#
# xml_get_fh()
#
# Return the output filehandle.
#
sub xml_get_fh {
my $self = shift;
return $self->{_fh};
}
###############################################################################
#
# _escape_attributes()
#
# Escape XML characters in attributes.
#
sub _escape_attributes {
my $str = $_[0];
return $str if $str !~ m/["&<>\n]/;
for ( $str ) {
s/&/&amp;/g;
s/"/&quot;/g;
s/</&lt;/g;
s/>/&gt;/g;
s/\n/&#xA;/g;
}
return $str;
}
###############################################################################
#
# _escape_data()
#
# Escape XML characters in data sections. Note, this is different from
# _escape_attributes() in that double quotes are not escaped by Excel.
#
sub _escape_data {
my $str = $_[0];
return $str if $str !~ m/[&<>]/;
for ( $str ) {
s/&/&amp;/g;
s/</&lt;/g;
s/>/&gt;/g;
}
return $str;
}
1;
__END__
=pod
=head1 NAME
XMLwriter - A base class for the Excel::Writer::XLSX writer classes.
=head1 DESCRIPTION
This module is used by L<Excel::Writer::XLSX> for writing XML documents. It is a light weight re-implementation of L<XML::Writer>.
XMLwriter is approximately twice as fast as L<XML::Writer>. This speed is achieved at the expense of error and correctness checking. In addition not all of the L<XML::Writer> methods are implemented. As such, XMLwriter is not recommended for use outside of Excel::Writer::XLSX.
=head1 SEE ALSO
L<XML::Writer>.
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
(c) MM-MMXX, John McNamara.
All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
=head1 LICENSE
Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut