package Spreadsheet::WriteExcelXML::XMLwriter;
###############################################################################
#
# XMLwriter - A base class for Excel workbooks and worksheets.
#
#
# Used in conjunction with Spreadsheet::WriteExcelXML
#
# Copyright 2000-2005, John McNamara, jmcnamara@cpan.org
#
# Documentation after __END__
#
use Exporter;
use strict;
use vars qw($VERSION @ISA);
@ISA = qw(Exporter);
$VERSION = '0.06';
###############################################################################
#
# new()
#
# Constructor
#
sub new {
my $class = $_[0];
my $self = {
_filehandle => $_[1],
_indentation => " ",
_no_encoding => 0,
};
bless $self, $class;
return $self;
}
###############################################################################
#
# _format_tag($level, $nl, $list, @attributes)
#
# This function formats an XML element tag for printing. Adds indentation and
# newlines as specified. Keeps attributes, if any, on one line or formats
# them one per line.
#
# Args:
# $level = The indentation level (int)
# $nl = Number of newlines after tag (int)
# $list = List attributes on separate lines (0, 1, 2)
# 0 = No list
# 1 = Automatic list
# 2 = Explicit list
# @attributes = Attribute/Value pairs
#
# The list option puts the attributes on separate lines if there is more
# than one attribute. List option 2 generates this effect even when there
# is only one attribute.
#
sub _format_tag {
my $self = shift;
my $level = shift;
my $nl = shift;
my $list = shift;
my $element = $self->{_indentation} x $level. '<' . shift;
# Autolist option. Only use list format if there is more than 1 attribute.
$list = 0 if $list == 1 and @_ <= 2;
# Special case. If _indentation is "" avoid all unnecessary whitespace
$list = 0 if $self->{_indentation} eq "";
$nl = 0 if $self->{_indentation} eq "";
while (@_) {
my $attrib = shift;
my $value = $self->_encode_xml_escapes(shift);
if ($list) {$element .= "\n" . $self->{_indentation} x ($level +1);}
else {$element .= ' '; }
$element .= $attrib;
$element .= '="' . $value . '"';
}
$nl = $nl ? "\n" x $nl : "";
return $element . '>'. $nl;
}
###############################################################################
#
# _encode_xml_escapes()
#
# Encode standard XML escapes, namely " & < > and \n. The apostrophe character
# isn't escaped since it will only occur in double quoted strings.
#
sub _encode_xml_escapes {
my $self = shift;
my $value = $_[0];
# Print un-encoded entities for debugging
return $value if $self->{_no_encoding};
for ($value) {
s/&/&/g;
s/</g;
s/>/>/g;
s/"/"/g; # "
#s/'/&pos;/g; # Not used
s/\n/
/g;
}
return $value;
}
###############################################################################
#
# _write_xml_start_tag()
#
# Creates a formatted XML opening tag. Prints to the current filehandle by
# default.
#
# Ex:
#
sub _write_xml_start_tag {
my $self = shift;
my $tag = $self->_format_tag(@_);
local $\; # Make print() ignore -l on the command line.
print {$self->{_filehandle}} $tag if $self->{_filehandle};
return $tag;
}
###############################################################################
#
# _write_xml_directive()
#
# Creates a formatted XML ?> directive. Prints to the current filehandle by
# default.
#
# Ex:
#
sub _write_xml_directive {
my $self = shift;
my $tag = $self->_format_tag(@_);
$tag =~ s[<][];
$tag =~ s[>][?>];
local $\; # Make print() ignore -l on the command line.
print {$self->{_filehandle}} $tag if $self->{_filehandle};
return $tag;
}
###############################################################################
#
# _write_xml_end_tag()
#
# Creates the closing tag of an XML element. Prints to the current filehandle
# by default.
#
# Ex:
#
sub _write_xml_end_tag {
my $self = shift;
my $tag = $self->_format_tag(@_);
$tag =~ s[<][];
local $\; # Make print() ignore -l on the command line.
print {$self->{_filehandle}} $tag if $self->{_filehandle};
return $tag;
}
###############################################################################
#
# _write_xml_element()
#
# Creates a single open and closed XML element. Prints to the current
# filehandle by default.
#
# Ex: or
#
sub _write_xml_element {
my $self = shift;
my $tag = $self->_format_tag(@_);
$tag =~ s[>][/>];
local $\; # Make print() ignore -l on the command line.
print {$self->{_filehandle}} $tag if $self->{_filehandle};
return $tag;
}
###############################################################################
#
# _write_xml_content()
#
# Creates an encoded XML element content. Prints to the current filehandle
# by default.
#
# Ex: Hello in Hello
#
sub _write_xml_content {
my $self = shift;
my $tag = $self->_encode_xml_escapes($_[0]);
local $\; # Make print() ignore -l on the command line.
print {$self->{_filehandle}} $tag if $self->{_filehandle};
return $tag;
}
###############################################################################
#
# _write_xml_unencoded_content()
#
# Creates an un-encoded XML element content. Prints to the current filehandle
# by default. Used for numerical or other data that doesn't need to be
# encoded.
#
# Ex: 1.2345 in 1.2345
#
sub _write_xml_unencoded_content {
my $self = shift;
my $tag = $_[0];
local $\; # Make print() ignore -l on the command line.
print {$self->{_filehandle}} $tag if $self->{_filehandle};
return $tag;
}
###############################################################################
#
# set_indentation()
#
# Set indentation string used to indent the output. The default is 4 spaces.
#
sub set_indentation {
my $self = shift;
$self->{_indentation} = defined $_[0] ? $_[0] : ' ';
}
1;
__END__
=head1 NAME
XMLwriter - A base class for Excel workbooks and worksheets.
=head1 SYNOPSIS
#!/usr/bin/perl -w
use strict;
use Spreadsheet::WriteExcelXML::XMLwriter;
my $writer = Spreadsheet::WriteExcelXML::XMLwriter->new(*STDOUT);
$writer->_write_xml_start_tag(0, 1, 0, 'Table', 'Rows', 4, 'Cols', 2);
$writer->_write_xml_element (1, 1, 0, 'Row', 'Index', '1');
$writer->_write_xml_end_tag (0, 1, 0, 'Table');
__END__
Prints:
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::WriteExcelXML. It is not intended to be a general purpose module.
As such this documentation is intended mainly for Spreadsheet::WriteExcelXML developers and maintainers.
=head1 METHODS
This section describes the methods of the C module.
=head2 set_indentation()
The C method is used to define the style of indentation used in the output from C. This is the only C method of the module.
The default indentation style is four spaces. Calling C with C or no argument will set the indentation style back to the default.
A special case argument is the null string C<''>. In addition to not adding any indentation this also overrides any newline settings so that the output is as compact as possible and in the form of a single line. This is useful for saving space or when streaming the output.
The following example shows some of the options:
#!/usr/bin/perl -w
use strict;
use Spreadsheet::WriteExcelXML::XMLwriter;
my $writer = Spreadsheet::WriteExcelXML::XMLwriter->new(*STDOUT);
# One space indent.
$writer->set_indentation(' ');
$writer->_write_xml_start_tag(1, 1, 1, 'Table');
$writer->_write_xml_start_tag(2, 1, 1, 'Row' );
$writer->_write_xml_start_tag(3, 1, 1, 'Cell' );
print "\n";
# Undef. Four space indent, the default.
$writer->set_indentation();
$writer->_write_xml_start_tag(1, 1, 1, 'Table');
$writer->_write_xml_start_tag(2, 1, 1, 'Row' );
$writer->_write_xml_start_tag(3, 1, 1, 'Cell' );
print "\n";
# Empty string. No indentation or newlines.
$writer->set_indentation('');
$writer->_write_xml_start_tag(1, 1, 1, 'Table');
$writer->_write_xml_start_tag(2, 1, 1, 'Row' );
$writer->_write_xml_start_tag(3, 1, 1, 'Cell' );
print "\n";
The output is as follows. Spaces shown as C<.> for clarity.
.
..
...
....
........
............
=head2 _format_tag($level, $nl, $list, @attributes)
This function formats an XML element tag for printing. This is a C method used by the C<_write_xml_xxx> methods. The C<_write_xml_xxx> methods can be considered as C and share the same parameters as C<_format_tag()>.
The parameters are as follows:
=over 4
=item C<$level>
The C<$level> parameter sets the indentation level. The type of indentation is defined using the set_indentation() method.
=item C<$nl>
The C<$nl> parameter sets the number of newlines after the tag.
=item C<$list>
The C<$list> parameter defines if element attributes are listed on more than one line. The value should be 0, 1 or 2 as follows:
=over 4
=item * 0
No list.
$writer->_format_tag(1, 1, 0, 'Foo', 'Color', 'red', 'Height', 12);
# Returns
=item * 1
Automatic list. This option puts the attributes on separate lines if there is more than one attribute.
# Implicit list (more than one attribute)
$writer->_format_tag(1, 1, 1, 'Foo', 'Color', 'red', 'Height', 12);
# Returns
# No implicit list (one attribute only)
$writer->_format_tag(1, 1, 1, 'Foo', 'Color', 'red');
# Returns
=item * 2
Explicit list. This option generates a list effect even when there is only one attribute.
$writer->_format_tag(1, 1, 2, 'Foo', 'Color', 'red');
# Returns
=back
=back
B: The C<$level>, C<$nl> and C<$list> parameters could be set as defaults in the C<_write_xml_xxx> methods. For example C<$level> could be incremented and decremented automatically, and C<$nl> and <$list> could be set to 1. The defaults could then be overridden on a per tag basis. However, we'll maintain the simpler direct approach for now.
=head2 _write_xml_start_tag()
Write an XML start tag with attributes if present. See the _format_tag() method for a list of the parameters.
$writer->_write_xml_start_tag(0, 0, 0, 'Table', 'Rows', 4, 'Cols', 2);
# Output
=head2 _write_xml_end_tag()
Write an XML end tag with attributes if present. See the _format_tag() method for a list of the parameters.
$writer->_write_xml_end_tag(0, 0, 0, 'Table');
# Output
=head2 _write_xml_element()
Write a complete XML tag with attributes if present. See the _format_tag() method for a list of the parameters.
$writer->_write_xml_element(0, 0, 0, 'Table', 'Rows', 4, 'Cols', 2);
# Output
=head2 _write_xml_directive()
Write an XML directive tag. See the _format_tag() method for a list of the parameters.
$writer->_write_xml_directive(0, 0, 0, 'xml', 'version', '1.0');
# Output
=head2 _write_xml_content()
Write the content section of a tag:
This is the content.
It encodes any XML escapes that occur in the content. See the C<_encode_xml_escapes> method.
=head2 _write_xml_unencoded_content()
This method is the same as C<> except that it doesn't try to encode. This is used mainly to save a small amount of time when writing data types that doesn't need to be encoded such as ENumberE.
=head2 _encode_xml_escapes()
Write some standard XML escapes, namely C<">, C<&>, C>, C> and C<\n>.
The apostrophe character isn't escaped since C always uses double quoted strings for attribute values.
print $writer->_encode_xml_escapes('foo < 3');
# Outputs
foo < 3
=head1 AUTHOR
John McNamara jmcnamara@cpan.org
=head1 COPYRIGHT
© MM-MMV, 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.
|
| |