The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

###############################################################################
#
# Excel::Writer::XLSX::Package::ContentTypes - A class for writing the Excel
# XLS [Content_Types] file.
#
# Used in conjunction with Excel::Writer::XLSX
#
# Copyright 2000-2024, John McNamara, jmcnamara@cpan.org
#
# SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
#
# Documentation after __END__
#
# perltidy with the following options: -mbl=2 -pt=0 -nola
use 5.008002;
use strict;
use Carp;
our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
our $VERSION = '1.14';
###############################################################################
#
# 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' );
}
###############################################################################
#
# _add_metadata()
#
# Add the metadata file to the ContentTypes overrides.
#
sub _add_metadata {
my $self = shift;
my $custom = "/xl/metadata.xml";
$self->_add_override( $custom,
$app_document . 'spreadsheetml.sheetMetadata+xml' );
}
###############################################################################
#
# _add_richvalue()
#
# Add the RichValue files to the ContentTypes overrides.
#
sub _add_richvalue {
my $self = shift;
$self->_add_override(
'/xl/richData/rdRichValueTypes.xml',
'application/vnd.ms-excel.rdrichvaluetypes+xml'
);
$self->_add_override(
'/xl/richData/rdrichvalue.xml',
'application/vnd.ms-excel.rdrichvalue+xml'
);
$self->_add_override(
'/xl/richData/rdrichvaluestructure.xml',
'application/vnd.ms-excel.rdrichvaluestructure+xml'
);
$self->_add_override(
'/xl/richData/richValueRel.xml',
'application/vnd.ms-excel.richvaluerel+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 @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-MMXXIV, 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<https://dev.perl.org/licenses/artistic.html> or the GNU General Public License v1.0 or later L<https://dev.perl.org/licenses/gpl1.html>.
=head1 DISCLAIMER OF WARRANTY
See the documentation for L<Excel::Writer::XLSX>.
=cut