META.yml for 0.21
[p5sagit/Excel-Template.git] / lib / Excel / Template.pm
CommitLineData
d0eafc11 1package Excel::Template;
2
3use strict;
4
5BEGIN {
6 use Excel::Template::Base;
7 use vars qw ($VERSION @ISA);
8
6dd4c89d 9 $VERSION = '0.21';
d0eafc11 10 @ISA = qw( Excel::Template::Base );
11}
12
13use File::Basename;
14use XML::Parser;
d0eafc11 15use IO::Scalar;
16
6dd4c89d 17use constant RENDER_NML => 'normal';
18use constant RENDER_BIG => 'big';
19use constant RENDER_XML => 'xml';
20
21my %renderers = (
22 RENDER_NML, 'Spreadsheet::WriteExcel',
23 RENDER_BIG, 'Spreadsheet::WriteExcel::Big',
24 RENDER_XML, 'Spreadsheet::WriteExcelXML',
25);
26
d0eafc11 27sub new
28{
29 my $class = shift;
30 my $self = $class->SUPER::new(@_);
31
32 $self->parse_xml($self->{FILENAME})
33 if defined $self->{FILENAME};
34
35 my @renderer_classes = ( 'Spreadsheet::WriteExcel' );
6dd4c89d 36
37 if (exists $self->{RENDERER} && $self->{RENDERER})
d0eafc11 38 {
6dd4c89d 39 if (exists $renderers{ lc $self->{RENDERER} })
40 {
41 unshift @renderer_classes, $renderers{ lc $self->{RENDERER} };
42 }
43 elsif ($^W)
44 {
45 warn "'$self->{RENDERER}' is not recognized\n";
46 }
d0eafc11 47 }
6dd4c89d 48 elsif (exists $self->{BIG_FILE} && $self->{BIG_FILE})
9d172425 49 {
6dd4c89d 50 warn "Use of BIG_FILE is deprecated.\n";
51 unshift @renderer_classes, 'Spreadsheet::WriteExcel::Big';
9d172425 52 }
53
d0eafc11 54 $self->{RENDERER} = undef;
55 foreach my $class (@renderer_classes)
56 {
57 (my $filename = $class) =~ s!::!/!g;
58 eval {
59 require "$filename.pm";
60 $class->import;
61 };
62 if ($@) {
dee1f239 63 warn "Could not find or compile '$class'\n" if $^W;
d0eafc11 64 } else {
65 $self->{RENDERER} = $class;
66 last;
67 }
68 }
69
70 defined $self->{RENDERER} ||
71 die "Could not find a renderer class. Tried:\n\t" .
72 join("\n\t", @renderer_classes) .
73 "\n";
74
8c63e224 75 $self->{USE_UNICODE} = ~~0
76 if $] >= 5.008;
77
d0eafc11 78 return $self;
79}
80
81sub param
82{
83 my $self = shift;
84
85 # Allow an arbitrary number of hashrefs, so long as they're the first things # into param(). Put each one onto the end, de-referenced.
86 push @_, %{shift @_} while UNIVERSAL::isa($_[0], 'HASH');
87
88 (@_ % 2)
89 && die __PACKAGE__, "->param() : Odd number of parameters to param()\n";
90
91 my %params = @_;
92 $params{uc $_} = delete $params{$_} for keys %params;
93 @{$self->{PARAM_MAP}}{keys %params} = @params{keys %params};
94
8c63e224 95 return ~~1;
d0eafc11 96}
97
98sub write_file
99{
100 my $self = shift;
101 my ($filename) = @_;
102
103 my $xls = $self->{RENDERER}->new($filename)
104 || die "Cannot create XLS in '$filename': $!\n";
105
106 $self->_prepare_output($xls);
107
108 $xls->close;
109
8c63e224 110 return ~~1;
d0eafc11 111}
112
113sub output
114{
115 my $self = shift;
116
117 my $output;
118 tie *XLS, 'IO::Scalar', \$output;
119
120 $self->write_file(\*XLS);
121
122 return $output;
123}
124
d0eafc11 125sub parse_xml
126{
127 my $self = shift;
128 my ($fname) = @_;
129
130 my ($filename, $dirname) = fileparse($fname);
131
132 my @stack;
133 my $parser = XML::Parser->new(
134 Base => $dirname,
135 Handlers => {
136 Start => sub {
137 shift;
138
139 my $name = uc shift;
140
6dd4c89d 141 my $node = Excel::Template::Factory->_create_node($name, @_);
d0eafc11 142 die "'$name' (@_) didn't make a node!\n" unless defined $node;
143
37513eae 144 if ( $node->isa( 'WORKBOOK' ) )
d0eafc11 145 {
146 push @{$self->{WORKBOOKS}}, $node;
147 }
37513eae 148 elsif ( $node->is_embedded )
d0eafc11 149 {
150 return unless @stack;
151
152 if (exists $stack[-1]{TXTOBJ} &&
153 $stack[-1]{TXTOBJ}->isa('TEXTOBJECT'))
154 {
155 push @{$stack[-1]{TXTOBJ}{STACK}}, $node;
156 }
157
158 }
159 else
160 {
161 push @{$stack[-1]{ELEMENTS}}, $node
162 if @stack;
163 }
164 push @stack, $node;
165 },
166 Char => sub {
167 shift;
168 return unless @stack;
169
170 my $parent = $stack[-1];
171
172 if (
173 exists $parent->{TXTOBJ}
174 &&
175 $parent->{TXTOBJ}->isa('TEXTOBJECT')
176 ) {
177 push @{$parent->{TXTOBJ}{STACK}}, @_;
178 }
179 },
180 End => sub {
181 shift;
182 return unless @stack;
183
184 pop @stack if $stack[-1]->isa(uc $_[0]);
185 },
186 },
187 );
188
189 {
b6bc5a5d 190 open( INFILE, "<$fname" )
d0eafc11 191 || die "Cannot open '$fname' for reading: $!\n";
192
b6bc5a5d 193 $parser->parse(do { local $/ = undef; <INFILE> });
d0eafc11 194
b6bc5a5d 195 close INFILE;
d0eafc11 196 }
197
8ca5e726 198 return ~~1;
d0eafc11 199}
b6bc5a5d 200*parse = \&parse_xml;
d0eafc11 201
202sub _prepare_output
203{
204 my $self = shift;
205 my ($xls) = @_;
206
6dd4c89d 207 my $context = Excel::Template::Factory->_create(
d0eafc11 208 'CONTEXT',
209
210 XLS => $xls,
211 PARAM_MAP => [ $self->{PARAM_MAP} ],
8c63e224 212 UNICODE => $self->{UNICODE},
d0eafc11 213 );
214
215 $_->render($context) for @{$self->{WORKBOOKS}};
216
8ca5e726 217 return ~~1;
d0eafc11 218}
219
220sub register { shift; Excel::Template::Factory::register(@_) }
221
2221;
223__END__
224
225=head1 NAME
226
227Excel::Template - Excel::Template
228
229=head1 SYNOPSIS
230
231First, make a template. This is an XML file, describing the layout of the
232spreadsheet.
233
234For example, test.xml:
235
236 <workbook>
237 <worksheet name="tester">
238 <cell text="$HOME"/>
239 <cell text="$PATH"/>
240 </worksheet>
241 </workbook>
242
243Now, create a small program to use it:
244
245 #!/usr/bin/perl -w
9d172425 246 use Excel::Template;
d0eafc11 247
248 # Create the Excel template
249 my $template = Excel::Template->new(
250 filename => 'test.xml',
251 );
252
253 # Add a few parameters
254 $template->param(
255 HOME => $ENV{HOME},
256 PATH => $ENV{PATH},
257 );
258
259 $template->write_file('test.xls');
260
261If everything worked, then you should have a spreadsheet in your work directory
262that looks something like:
263
264 A B C
265 +----------------+----------------+----------------
266 1 | /home/me | /bin:/usr/bin |
267 +----------------+----------------+----------------
268 2 | | |
269 +----------------+----------------+----------------
270 3 | | |
271
272=head1 DESCRIPTION
273
274This is a module used for templating Excel files. Its genesis came from the
275need to use the same datastructure as HTML::Template, but provide Excel files
276instead. The existing modules don't do the trick, as they require replication
277of logic that's already been done within HTML::Template.
278
d0eafc11 279=head1 MOTIVATION
280
281I do a lot of Perl/CGI for reporting purposes. In nearly every place I've been,
282I've been asked for HTML, PDF, and Excel. HTML::Template provides the first, and
283PDF::Template does the second pretty well. But, generating Excel was the
284sticking point. I already had the data structure for the other templating
285modules, but I just didn't have an easy mechanism to get that data structure
286into an XLS file.
287
288=head1 USAGE
289
290=head2 new()
291
8ca5e726 292This creates a Excel::Template object. If passed a FILENAME parameter, it will
d0eafc11 293parse the template in the given file. (You can also use the parse() method,
294described below.)
295
6dd4c89d 296=head3 Parameters
297
298=over 4
299
300=item * RENDERER
301
302The default rendering engine is Spreadsheet::WriteExcel. You may, if you choose, change that to another choice. The legal values are:
303
304=over 4
305
306=item * Excel::Template->RENDER_NML
307
308This is the default of Spreadsheet::WriteExcel.
8c63e224 309
6dd4c89d 310=item * Excel::Template->RENDER_BIG
311
312This attempts to load Spreadsheet::WriteExcel::Big.
313
314=item * Excel::Template->RENDER_XML
315
316This attempts to load Spreadsheet::WriteExcelXML.
317
318=back
319
320=item * USE_UNICODE
321
322This will use L<Unicode::String> to represent strings instead of Perl's internal string handling. You must already have L<Unicode::String> installed on your system.
8c63e224 323
324The USE_UNICODE parameter will be ignored if you are using Perl 5.8 or higher as
325Perl's internal string handling is unicode-aware.
8ca5e726 326
9d172425 327NOTE: Certain older versions of L<OLE::Storage_Lite> and mod_perl clash for some
328reason. Upgrading to the latest version of L<OLE::Storage_Lite> should fix the
329problem.
8ca5e726 330
6dd4c89d 331=back
332
333=head3 Deprecated
334
335=over 4
336
337=item * BIG_FILE
338
339Instead, use RENDERER => Excel::Template->RENDER_BIG
340
341=back
342
d0eafc11 343=head2 param()
344
8ca5e726 345This method is exactly like L<HTML::Template>'s param() method.
d0eafc11 346
347=head2 parse() / parse_xml()
348
349This method actually parses the template file. It can either be called
350separately or through the new() call. It will die() if it runs into a situation
351it cannot handle.
352
353=head2 write_file()
354
355Create the Excel file and write it to the specified filename, if possible. (This
356is when the actual merging of the template and the parameters occurs.)
357
358=head2 output()
359
360It will act just like HTML::Template's output() method, returning the resultant
361file as a stream, usually for output to the web. (This is when the actual
362merging of the template and the parameters occurs.)
363
6dd4c89d 364=head2 register()
365
366This allows you to register a class as handling a node. q.v. L<Excel::Template::Factory> for more info.
367
d0eafc11 368=head1 SUPPORTED NODES
369
8ca5e726 370This is a partial list of nodes. See the other classes in this distro for more
d0eafc11 371details on specific parameters and the like.
372
373Every node can set the ROW and COL parameters. These are the actual ROW/COL
8ca5e726 374values that the next CELL-type tag will write into.
d0eafc11 375
376=over 4
377
8ca5e726 378=item * L<WORKBOOK|Excel::Template::Container::Workbook>
379
380This is the node representing the workbook. It is the parent for all other
381nodes.
382
383=item * L<WORKSHEET|Excel::Template::Container::Worksheet>
384
385This is the node representing a given worksheet.
386
387=item * L<IF|Excel::Template::Container::Conditional>
388
389This node represents a conditional expression. Its children may or may not be
390rendered. It behaves just like L<HTML::Template>'s TMPL_IF.
391
392=item * L<LOOP|Excel::Template::Container::Loop>
393
394This node represents a loop. It behaves just like L<HTML::Template>'s TMPL_LOOP.
395
396=item * L<ROW|Excel::Template::Container::Row>
397
398This node represents a row of data. This is the A in A1.
399
400=item * L<FORMAT|Excel::Template::Container::Format>
401
402This node varies the format for its children. All formatting options supported
403in L<Spreadsheet::WriteExcel> are supported here. There are also a number of
404formatting shortcuts, such as L<BOLD|Excel::Template::Container::Bold> and
405L<ITALIC|Excel::Template::Container::Italic>.
406
407=item * L<BACKREF|Excel::Template::Element::Backref>
408
409This refers back to a cell previously named.
d0eafc11 410
8ca5e726 411=item * L<CELL|Excel::Template::Element::Cell>
d0eafc11 412
8ca5e726 413This is the actual cell in a spreadsheet.
d0eafc11 414
8ca5e726 415=item * L<FORMULA|Excel::Template::Element::Formula>
d0eafc11 416
8ca5e726 417This is a formula in a spreadsheet.
d0eafc11 418
8ca5e726 419=item * L<RANGE|Excel::Template::Element::Range>
d0eafc11 420
8ca5e726 421This is a BACKREF for a number of identically-named cells.
d0eafc11 422
8ca5e726 423=item * L<VAR|Excel::Template::Element::Var>
d0eafc11 424
8ca5e726 425This is a variable. It is generally used when the 'text' attribute isn't
426sufficient.
d0eafc11 427
6dd4c89d 428=back
d0eafc11 429
430=head1 BUGS
431
432None, that I know of.
433
434=head1 SUPPORT
435
8ca5e726 436This is production quality software, used in several production web
437applications.
d0eafc11 438
439=head1 AUTHOR
440
8ca5e726 441 Rob Kinyon (rob.kinyon@gmail.com)
a8441e01 442
443=head1 CONTRIBUTORS
444
c11fa570 445There is a mailing list at http://groups.google.com/group/ExcelTemplate or exceltemplate@googlegroups.com
d0eafc11 446
c11fa570 447=head2 Robert Graff
37513eae 448
449=over 4
450
451=item * Finishing formats
452
453=item * Fixing several bugs in worksheet naming
454
6dd4c89d 455=back
37513eae 456
c11fa570 457=head1 TEST COVERAGE
458
459I used Devel::Cover to test the coverage of my tests. Every release, I intend to improve these numbers.
460
461Excel::Template is also part of the CPAN Kwalitee initiative, being one of the top 100 non-core modules downloaded from CPAN. If you wish to help out, please feel free to contribute tests, patches, and/or suggestions.
462
463---------------------------- ------ ------ ------ ------ ------ ------ ------
464File stmt branch cond sub pod time total
465---------------------------- ------ ------ ------ ------ ------ ------ ------
466blib/lib/Excel/Template.pm 90.0 57.1 50.0 90.5 100.0 26.0 80.8
467...ib/Excel/Template/Base.pm 83.3 50.0 66.7 75.0 88.9 8.8 80.0
468...cel/Template/Container.pm 46.3 20.0 33.3 58.3 85.7 4.6 47.7
469...emplate/Container/Bold.pm 100.0 n/a n/a 100.0 0.0 0.6 95.0
470.../Container/Conditional.pm 58.5 52.3 66.7 75.0 66.7 0.7 58.4
471...plate/Container/Format.pm 100.0 n/a n/a 100.0 0.0 0.8 96.6
472...plate/Container/Hidden.pm 100.0 n/a n/a 100.0 0.0 0.2 95.0
473...plate/Container/Italic.pm 100.0 n/a n/a 100.0 0.0 0.2 95.0
474...plate/Container/Locked.pm 100.0 n/a n/a 100.0 0.0 0.1 95.0
475...emplate/Container/Loop.pm 55.6 40.0 50.0 77.8 75.0 0.5 56.6
476...late/Container/Outline.pm 71.4 n/a n/a 80.0 0.0 0.0 70.0
477...Template/Container/Row.pm 100.0 75.0 n/a 100.0 50.0 0.3 93.8
478...mplate/Container/Scope.pm 100.0 n/a n/a 100.0 n/a 0.1 100.0
479...plate/Container/Shadow.pm 100.0 n/a n/a 100.0 0.0 0.1 95.0
480...te/Container/Strikeout.pm 100.0 n/a n/a 100.0 0.0 0.1 95.0
481...ate/Container/Workbook.pm 100.0 n/a n/a 100.0 n/a 1.1 100.0
482...te/Container/Worksheet.pm 94.1 50.0 n/a 100.0 0.0 0.9 88.0
483...Excel/Template/Context.pm 83.1 53.4 54.2 95.0 92.9 19.2 75.2
484...Excel/Template/Element.pm 100.0 n/a n/a 100.0 n/a 0.5 100.0
485...mplate/Element/Backref.pm 100.0 50.0 33.3 100.0 0.0 0.1 87.1
486.../Template/Element/Cell.pm 95.8 65.0 80.0 100.0 66.7 3.6 86.9
487...mplate/Element/Formula.pm 100.0 n/a n/a 100.0 0.0 0.3 94.1
488...Template/Element/Range.pm 100.0 66.7 n/a 100.0 66.7 0.2 93.3
489...l/Template/Element/Var.pm 100.0 n/a n/a 100.0 0.0 0.2 94.1
490...Excel/Template/Factory.pm 57.1 34.6 n/a 88.9 100.0 15.4 55.2
491.../Excel/Template/Format.pm 98.3 81.2 33.3 100.0 100.0 9.9 93.2
492...xcel/Template/Iterator.pm 85.2 70.6 70.6 84.6 87.5 2.0 80.4
493...el/Template/TextObject.pm 92.9 62.5 33.3 100.0 50.0 3.6 83.0
494Total 83.0 55.6 57.0 91.1 98.7 100.0 78.6
495---------------------------- ------ ------ ------ ------ ------ ------ ------
496
d0eafc11 497=head1 COPYRIGHT
498
499This program is free software; you can redistribute
500it and/or modify it under the same terms as Perl itself.
501
502The full text of the license can be found in the
503LICENSE file included with this module.
504
505=head1 SEE ALSO
506
507perl(1), HTML::Template, Spreadsheet::WriteExcel.
508
509=cut