Fixed minor installation and documentation issues
[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
8ca5e726 9 $VERSION = '0.19';
d0eafc11 10 @ISA = qw( Excel::Template::Base );
11}
12
13use File::Basename;
14use XML::Parser;
d0eafc11 15use IO::Scalar;
16
17sub new
18{
19 my $class = shift;
20 my $self = $class->SUPER::new(@_);
21
22 $self->parse_xml($self->{FILENAME})
23 if defined $self->{FILENAME};
24
25 my @renderer_classes = ( 'Spreadsheet::WriteExcel' );
26 if (exists $self->{BIG_FILE} && $self->{BIG_FILE})
27 {
28 unshift @renderer_classes, 'Spreadsheet::WriteExcel::Big';
29 }
30
31 $self->{RENDERER} = undef;
32 foreach my $class (@renderer_classes)
33 {
34 (my $filename = $class) =~ s!::!/!g;
35 eval {
36 require "$filename.pm";
37 $class->import;
38 };
39 if ($@) {
dee1f239 40 warn "Could not find or compile '$class'\n" if $^W;
d0eafc11 41 } else {
42 $self->{RENDERER} = $class;
43 last;
44 }
45 }
46
47 defined $self->{RENDERER} ||
48 die "Could not find a renderer class. Tried:\n\t" .
49 join("\n\t", @renderer_classes) .
50 "\n";
51
52 return $self;
53}
54
55sub param
56{
57 my $self = shift;
58
59 # Allow an arbitrary number of hashrefs, so long as they're the first things # into param(). Put each one onto the end, de-referenced.
60 push @_, %{shift @_} while UNIVERSAL::isa($_[0], 'HASH');
61
62 (@_ % 2)
63 && die __PACKAGE__, "->param() : Odd number of parameters to param()\n";
64
65 my %params = @_;
66 $params{uc $_} = delete $params{$_} for keys %params;
67 @{$self->{PARAM_MAP}}{keys %params} = @params{keys %params};
68
b6bc5a5d 69 return !!1;
d0eafc11 70}
71
72sub write_file
73{
74 my $self = shift;
75 my ($filename) = @_;
76
77 my $xls = $self->{RENDERER}->new($filename)
78 || die "Cannot create XLS in '$filename': $!\n";
79
80 $self->_prepare_output($xls);
81
82 $xls->close;
83
b6bc5a5d 84 return !!1;
d0eafc11 85}
86
87sub output
88{
89 my $self = shift;
90
91 my $output;
92 tie *XLS, 'IO::Scalar', \$output;
93
94 $self->write_file(\*XLS);
95
96 return $output;
97}
98
d0eafc11 99sub parse_xml
100{
101 my $self = shift;
102 my ($fname) = @_;
103
104 my ($filename, $dirname) = fileparse($fname);
105
106 my @stack;
107 my $parser = XML::Parser->new(
108 Base => $dirname,
109 Handlers => {
110 Start => sub {
111 shift;
112
113 my $name = uc shift;
114
115 my $node = Excel::Template::Factory->create_node($name, @_);
116 die "'$name' (@_) didn't make a node!\n" unless defined $node;
117
37513eae 118 if ( $node->isa( 'WORKBOOK' ) )
d0eafc11 119 {
120 push @{$self->{WORKBOOKS}}, $node;
121 }
37513eae 122 elsif ( $node->is_embedded )
d0eafc11 123 {
124 return unless @stack;
125
126 if (exists $stack[-1]{TXTOBJ} &&
127 $stack[-1]{TXTOBJ}->isa('TEXTOBJECT'))
128 {
129 push @{$stack[-1]{TXTOBJ}{STACK}}, $node;
130 }
131
132 }
133 else
134 {
135 push @{$stack[-1]{ELEMENTS}}, $node
136 if @stack;
137 }
138 push @stack, $node;
139 },
140 Char => sub {
141 shift;
142 return unless @stack;
143
144 my $parent = $stack[-1];
145
146 if (
147 exists $parent->{TXTOBJ}
148 &&
149 $parent->{TXTOBJ}->isa('TEXTOBJECT')
150 ) {
151 push @{$parent->{TXTOBJ}{STACK}}, @_;
152 }
153 },
154 End => sub {
155 shift;
156 return unless @stack;
157
158 pop @stack if $stack[-1]->isa(uc $_[0]);
159 },
160 },
161 );
162
163 {
b6bc5a5d 164 open( INFILE, "<$fname" )
d0eafc11 165 || die "Cannot open '$fname' for reading: $!\n";
166
b6bc5a5d 167 $parser->parse(do { local $/ = undef; <INFILE> });
d0eafc11 168
b6bc5a5d 169 close INFILE;
d0eafc11 170 }
171
8ca5e726 172 return ~~1;
d0eafc11 173}
b6bc5a5d 174*parse = \&parse_xml;
d0eafc11 175
176sub _prepare_output
177{
178 my $self = shift;
179 my ($xls) = @_;
180
181 my $context = Excel::Template::Factory->create(
182 'CONTEXT',
183
184 XLS => $xls,
185 PARAM_MAP => [ $self->{PARAM_MAP} ],
186 );
187
188 $_->render($context) for @{$self->{WORKBOOKS}};
189
8ca5e726 190 return ~~1;
d0eafc11 191}
192
193sub register { shift; Excel::Template::Factory::register(@_) }
194
1951;
196__END__
197
198=head1 NAME
199
200Excel::Template - Excel::Template
201
202=head1 SYNOPSIS
203
204First, make a template. This is an XML file, describing the layout of the
205spreadsheet.
206
207For example, test.xml:
208
209 <workbook>
210 <worksheet name="tester">
211 <cell text="$HOME"/>
212 <cell text="$PATH"/>
213 </worksheet>
214 </workbook>
215
216Now, create a small program to use it:
217
218 #!/usr/bin/perl -w
219 use Excel::Template
220
221 # Create the Excel template
222 my $template = Excel::Template->new(
223 filename => 'test.xml',
224 );
225
226 # Add a few parameters
227 $template->param(
228 HOME => $ENV{HOME},
229 PATH => $ENV{PATH},
230 );
231
232 $template->write_file('test.xls');
233
234If everything worked, then you should have a spreadsheet in your work directory
235that looks something like:
236
237 A B C
238 +----------------+----------------+----------------
239 1 | /home/me | /bin:/usr/bin |
240 +----------------+----------------+----------------
241 2 | | |
242 +----------------+----------------+----------------
243 3 | | |
244
245=head1 DESCRIPTION
246
247This is a module used for templating Excel files. Its genesis came from the
248need to use the same datastructure as HTML::Template, but provide Excel files
249instead. The existing modules don't do the trick, as they require replication
250of logic that's already been done within HTML::Template.
251
d0eafc11 252=head1 MOTIVATION
253
254I do a lot of Perl/CGI for reporting purposes. In nearly every place I've been,
255I've been asked for HTML, PDF, and Excel. HTML::Template provides the first, and
256PDF::Template does the second pretty well. But, generating Excel was the
257sticking point. I already had the data structure for the other templating
258modules, but I just didn't have an easy mechanism to get that data structure
259into an XLS file.
260
261=head1 USAGE
262
263=head2 new()
264
8ca5e726 265This creates a Excel::Template object. If passed a FILENAME parameter, it will
d0eafc11 266parse the template in the given file. (You can also use the parse() method,
267described below.)
268
8ca5e726 269new() accepts an optional BIG_FILE parameter. This will attempt to change the
270renderer from L<Spreadsheet::WriteExcel> to L<Spreadsheet::WriteExcel::Big>. You
271must have L<Spreadsheet::WriteExcel::Big> installed on your system.
272
273NOTE: L<Spreadsheet::WriteExcel::Big> and mod_perl clash for some reason. This
274is outside of my control.
275
d0eafc11 276=head2 param()
277
8ca5e726 278This method is exactly like L<HTML::Template>'s param() method.
d0eafc11 279
280=head2 parse() / parse_xml()
281
282This method actually parses the template file. It can either be called
283separately or through the new() call. It will die() if it runs into a situation
284it cannot handle.
285
286=head2 write_file()
287
288Create the Excel file and write it to the specified filename, if possible. (This
289is when the actual merging of the template and the parameters occurs.)
290
291=head2 output()
292
293It will act just like HTML::Template's output() method, returning the resultant
294file as a stream, usually for output to the web. (This is when the actual
295merging of the template and the parameters occurs.)
296
297=head1 SUPPORTED NODES
298
8ca5e726 299This is a partial list of nodes. See the other classes in this distro for more
d0eafc11 300details on specific parameters and the like.
301
302Every node can set the ROW and COL parameters. These are the actual ROW/COL
8ca5e726 303values that the next CELL-type tag will write into.
d0eafc11 304
305=over 4
306
8ca5e726 307=item * L<WORKBOOK|Excel::Template::Container::Workbook>
308
309This is the node representing the workbook. It is the parent for all other
310nodes.
311
312=item * L<WORKSHEET|Excel::Template::Container::Worksheet>
313
314This is the node representing a given worksheet.
315
316=item * L<IF|Excel::Template::Container::Conditional>
317
318This node represents a conditional expression. Its children may or may not be
319rendered. It behaves just like L<HTML::Template>'s TMPL_IF.
320
321=item * L<LOOP|Excel::Template::Container::Loop>
322
323This node represents a loop. It behaves just like L<HTML::Template>'s TMPL_LOOP.
324
325=item * L<ROW|Excel::Template::Container::Row>
326
327This node represents a row of data. This is the A in A1.
328
329=item * L<FORMAT|Excel::Template::Container::Format>
330
331This node varies the format for its children. All formatting options supported
332in L<Spreadsheet::WriteExcel> are supported here. There are also a number of
333formatting shortcuts, such as L<BOLD|Excel::Template::Container::Bold> and
334L<ITALIC|Excel::Template::Container::Italic>.
335
336=item * L<BACKREF|Excel::Template::Element::Backref>
337
338This refers back to a cell previously named.
d0eafc11 339
8ca5e726 340=item * L<CELL|Excel::Template::Element::Cell>
d0eafc11 341
8ca5e726 342This is the actual cell in a spreadsheet.
d0eafc11 343
8ca5e726 344=item * L<FORMULA|Excel::Template::Element::Formula>
d0eafc11 345
8ca5e726 346This is a formula in a spreadsheet.
d0eafc11 347
8ca5e726 348=item * L<RANGE|Excel::Template::Element::Range>
d0eafc11 349
8ca5e726 350This is a BACKREF for a number of identically-named cells.
d0eafc11 351
8ca5e726 352=item * L<VAR|Excel::Template::Element::Var>
d0eafc11 353
8ca5e726 354This is a variable. It is generally used when the 'text' attribute isn't
355sufficient.
d0eafc11 356
357=back 4
358
359=head1 BUGS
360
361None, that I know of.
362
363=head1 SUPPORT
364
8ca5e726 365This is production quality software, used in several production web
366applications.
d0eafc11 367
368=head1 AUTHOR
369
8ca5e726 370 Rob Kinyon (rob.kinyon@gmail.com)
a8441e01 371
372=head1 CONTRIBUTORS
373
8ca5e726 374There is a mailing list at http://groups.google.com/group/ExcelTemplate
d0eafc11 375
37513eae 376Robert Graff -
377
378=over 4
379
380=item * Finishing formats
381
382=item * Fixing several bugs in worksheet naming
383
384=back 4
385
d0eafc11 386=head1 COPYRIGHT
387
388This program is free software; you can redistribute
389it and/or modify it under the same terms as Perl itself.
390
391The full text of the license can be found in the
392LICENSE file included with this module.
393
394=head1 SEE ALSO
395
396perl(1), HTML::Template, Spreadsheet::WriteExcel.
397
398=cut