Commit | Line | Data |
3fea05b9 |
1 | .\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.3 |
2 | .\" |
3 | .\" Standard preamble: |
4 | .\" ======================================================================== |
5 | .de Sh \" Subsection heading |
6 | .br |
7 | .if t .Sp |
8 | .ne 5 |
9 | .PP |
10 | \fB\\$1\fR |
11 | .PP |
12 | .. |
13 | .de Sp \" Vertical space (when we can't use .PP) |
14 | .if t .sp .5v |
15 | .if n .sp |
16 | .. |
17 | .de Vb \" Begin verbatim text |
18 | .ft CW |
19 | .nf |
20 | .ne \\$1 |
21 | .. |
22 | .de Ve \" End verbatim text |
23 | .ft R |
24 | .fi |
25 | .. |
26 | .\" Set up some character translations and predefined strings. \*(-- will |
27 | .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left |
28 | .\" double quote, and \*(R" will give a right double quote. | will give a |
29 | .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to |
30 | .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' |
31 | .\" expand to `' in nroff, nothing in troff, for use with C<>. |
32 | .tr \(*W-|\(bv\*(Tr |
33 | .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' |
34 | .ie n \{\ |
35 | . ds -- \(*W- |
36 | . ds PI pi |
37 | . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch |
38 | . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch |
39 | . ds L" "" |
40 | . ds R" "" |
41 | . ds C` "" |
42 | . ds C' "" |
43 | 'br\} |
44 | .el\{\ |
45 | . ds -- \|\(em\| |
46 | . ds PI \(*p |
47 | . ds L" `` |
48 | . ds R" '' |
49 | 'br\} |
50 | .\" |
51 | .\" If the F register is turned on, we'll generate index entries on stderr for |
52 | .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index |
53 | .\" entries marked with X<> in POD. Of course, you'll have to process the |
54 | .\" output yourself in some meaningful fashion. |
55 | .if \nF \{\ |
56 | . de IX |
57 | . tm Index:\\$1\t\\n%\t"\\$2" |
58 | .. |
59 | . nr % 0 |
60 | . rr F |
61 | .\} |
62 | .\" |
63 | .\" For nroff, turn off justification. Always turn off hyphenation; it makes |
64 | .\" way too many mistakes in technical documents. |
65 | .hy 0 |
66 | .if n .na |
67 | .\" |
68 | .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). |
69 | .\" Fear. Run. Save yourself. No user-serviceable parts. |
70 | . \" fudge factors for nroff and troff |
71 | .if n \{\ |
72 | . ds #H 0 |
73 | . ds #V .8m |
74 | . ds #F .3m |
75 | . ds #[ \f1 |
76 | . ds #] \fP |
77 | .\} |
78 | .if t \{\ |
79 | . ds #H ((1u-(\\\\n(.fu%2u))*.13m) |
80 | . ds #V .6m |
81 | . ds #F 0 |
82 | . ds #[ \& |
83 | . ds #] \& |
84 | .\} |
85 | . \" simple accents for nroff and troff |
86 | .if n \{\ |
87 | . ds ' \& |
88 | . ds ` \& |
89 | . ds ^ \& |
90 | . ds , \& |
91 | . ds ~ ~ |
92 | . ds / |
93 | .\} |
94 | .if t \{\ |
95 | . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" |
96 | . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' |
97 | . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' |
98 | . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' |
99 | . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' |
100 | . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' |
101 | .\} |
102 | . \" troff and (daisy-wheel) nroff accents |
103 | .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' |
104 | .ds 8 \h'\*(#H'\(*b\h'-\*(#H' |
105 | .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] |
106 | .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' |
107 | .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' |
108 | .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] |
109 | .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] |
110 | .ds ae a\h'-(\w'a'u*4/10)'e |
111 | .ds Ae A\h'-(\w'A'u*4/10)'E |
112 | . \" corrections for vroff |
113 | .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' |
114 | .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' |
115 | . \" for low resolution devices (crt and lpr) |
116 | .if \n(.H>23 .if \n(.V>19 \ |
117 | \{\ |
118 | . ds : e |
119 | . ds 8 ss |
120 | . ds o a |
121 | . ds d- d\h'-1'\(ga |
122 | . ds D- D\h'-1'\(hy |
123 | . ds th \o'bp' |
124 | . ds Th \o'LP' |
125 | . ds ae ae |
126 | . ds Ae AE |
127 | .\} |
128 | .rm #[ #] #H #V #F C |
129 | .\" ======================================================================== |
130 | .\" |
131 | .IX Title "Template::Tutorial::Datafile 3" |
132 | .TH Template::Tutorial::Datafile 3 "2008-11-13" "perl v5.8.7" "User Contributed Perl Documentation" |
133 | .SH "NAME" |
134 | Template::Tutorial::Datafile \- Creating Data Output Files Using the Template Toolkit |
135 | .SH "DESCRIPTION" |
136 | .IX Header "DESCRIPTION" |
137 | .SH "Introducing the Template Toolkit" |
138 | .IX Header "Introducing the Template Toolkit" |
139 | There are a number of Perl modules that are universally |
140 | recognised as The Right Thing To Use for certain tasks. If you |
141 | accessed a database without using \s-1DBI\s0, pulled data from the \s-1WWW\s0 |
142 | without using one of the \s-1LWP\s0 modules or parsed \s-1XML\s0 without using |
143 | XML::Parser or one of its subclasses then you'd run the risk of |
144 | being shunned by polite Perl society. |
145 | .PP |
146 | I believe that the year 2000 saw the emergence of another 'must |
147 | have' Perl module \- the Template Toolkit. I don't think I'm |
148 | alone in this belief as the Template Toolkit won the 'Best New |
149 | Module' award at the Perl Conference last summer. Version 2.0 of |
150 | the Template Toolkit (known as \s-1TT2\s0 to its friends) was recently |
151 | released to the \s-1CPAN\s0. |
152 | .PP |
153 | \&\s-1TT2\s0 was designed and written by Andy Wardley <abw@wardley.org>. |
154 | It was born out of Andy's previous templating module, |
155 | Text::Metatext, in best Fred Brooks 'plan to throw one away' |
156 | manner; and aims to be the most useful (or, at least, the most |
157 | \&\fIused\fR) Perl templating system. |
158 | .PP |
159 | \&\s-1TT2\s0 provides a way to take a file of fixed boilerplate text |
160 | (the template) and embed variable data within it. One obvious |
161 | use of this is in the creation of dynamic web pages and this is |
162 | where a lot of the attention that \s-1TT2\s0 has received has been |
163 | focussed. In this article, I hope to demonstrate that \s-1TT2\s0 is |
164 | just as useful in non-web applications. |
165 | .SH "Using the Template Toolkit" |
166 | .IX Header "Using the Template Toolkit" |
167 | Let's look at how we'd use \s-1TT2\s0 to process a simple data file. |
168 | \&\s-1TT2\s0 is an object oriented Perl module. Having downloaded it from |
169 | \&\s-1CPAN\s0 and installed it in the usual manner, using it in your |
170 | program is as easy as putting the lines |
171 | .PP |
172 | .Vb 2 |
173 | \& use Template; |
174 | \& my $tt = Template\->new; |
175 | .Ve |
176 | .PP |
177 | in your code. The constructor function, \f(CW\*(C`new\*(C'\fR, takes |
178 | a number of optional parameters which are documented in the |
179 | copious manual pages that come with the module, but for the |
180 | purposes of this article we'll keep things as simple as |
181 | possible. |
182 | .PP |
183 | To process the template, you would call the \f(CW\*(C`process\*(C'\fR method |
184 | like this |
185 | .PP |
186 | .Vb 2 |
187 | \& $tt\->process('my_template', \e%data) |
188 | \& || die $tt\->error; |
189 | .Ve |
190 | .PP |
191 | We pass two parameters to \f(CW\*(C`process\*(C'\fR, the first is the name of |
192 | the file containing the template to process (in this case, |
193 | my_template) and the second is a reference to a hash which |
194 | contains the data items that you want to use in the template. If |
195 | processing the template gives any kind of error, the program |
196 | will die with a (hopefully) useful error message. |
197 | .PP |
198 | So what kinds of things can go in \f(CW%data\fR? The answer is just |
199 | about anything. Here's an example showing data about English |
200 | Premier League football teams. |
201 | .PP |
202 | .Vb 10 |
203 | \& my @teams = ({ name => 'Man Utd', |
204 | \& played => 16, |
205 | \& won => 12, |
206 | \& drawn => 3, |
207 | \& lost => 1 }, |
208 | \& { name => 'Bradford', |
209 | \& played => 16, |
210 | \& won => 2, |
211 | \& drawn => 5, |
212 | \& lost => 9 }); |
213 | .Ve |
214 | .PP |
215 | .Vb 3 |
216 | \& my %data = ( name => 'English Premier League', |
217 | \& season => '2000/01', |
218 | \& teams => \e@teams ); |
219 | .Ve |
220 | .PP |
221 | This creates three data items which can be accessed within the |
222 | template, called \f(CW\*(C`name\*(C'\fR, \f(CW\*(C`season\*(C'\fR and \f(CW\*(C`teams\*(C'\fR. Notice that |
223 | \&\f(CW\*(C`teams\*(C'\fR is a complex data structure. |
224 | .PP |
225 | Here is a template that we might use to process this data. |
226 | .PP |
227 | .Vb 1 |
228 | \& League Standings |
229 | .Ve |
230 | .PP |
231 | .Vb 2 |
232 | \& League Name: [% name %] |
233 | \& Season : [% season %] |
234 | .Ve |
235 | .PP |
236 | .Vb 5 |
237 | \& Teams: |
238 | \& [% FOREACH team = teams \-%] |
239 | \& [% team.name %] [% team.played \-%] |
240 | \& [% team.won %] [% team.drawn %] [% team.lost %] |
241 | \& [% END %] |
242 | .Ve |
243 | .PP |
244 | Running this template with this data gives us the following |
245 | output |
246 | .PP |
247 | .Vb 1 |
248 | \& League Standings |
249 | .Ve |
250 | .PP |
251 | .Vb 2 |
252 | \& League Name: English Premier League |
253 | \& Season : 2000/01 |
254 | .Ve |
255 | .PP |
256 | .Vb 3 |
257 | \& Teams: |
258 | \& Man Utd 16 12 3 1 |
259 | \& Bradford 16 2 5 9 |
260 | .Ve |
261 | .PP |
262 | Hopefully the syntax of the template is simple enough to |
263 | follow. There are a few points to note. |
264 | .IP "\(bu" 4 |
265 | Template processing directives are written using a simple |
266 | language which is not Perl. |
267 | .IP "\(bu" 4 |
268 | The keys of the \f(CW%data\fR have become the names of the data |
269 | variables within the template. |
270 | .IP "\(bu" 4 |
271 | Template processing directives are surrounded by \f(CW\*(C`[%\*(C'\fR and |
272 | \&\f(CW\*(C`%]\*(C'\fR sequences. |
273 | .IP "\(bu" 4 |
274 | If these tags are replaced with \f(CW\*(C`[%\-\*(C'\fR \f(CW\*(C`\-%]\*(C'\fR then the preceding |
275 | or following linefeed is suppressed. |
276 | .IP "\(bu" 4 |
277 | In the \f(CW\*(C`FOREACH\*(C'\fR loop, each element of the \f(CW\*(C`teams\*(C'\fR list was |
278 | assigned, in turn, to the temporary variable \f(CW\*(C`team\*(C'\fR. |
279 | .IP "\(bu" 4 |
280 | Each item assigned to the \f(CW\*(C`team\*(C'\fR variable is a Perl hash. |
281 | Individual values within the hash are accessed using a dot notation. |
282 | .PP |
283 | It's probably the first and last of these points which are the |
284 | most important. The first point emphasises the separation of the |
285 | data acquisition logic from the presentation logic. The person |
286 | creating the presentation template doesn't need to know Perl, |
287 | they only need to know the data items which will be passed into |
288 | the template. |
289 | .PP |
290 | The last point demonstrates the way that \s-1TT2\s0 protects the |
291 | template designer from the implementation of the data structures. |
292 | The data objects passed to the template processor can be scalars, |
293 | arrays, hashes, objects or even subroutines. The template |
294 | processor will just interpret your data correctly and Do The |
295 | Right Thing to return the correct value to you. In this example |
296 | each team was a hash, but in a larger system each team might be |
297 | an object, in which case \f(CW\*(C`name\*(C'\fR, \f(CW\*(C`played\*(C'\fR, etc. would be accessor |
298 | methods to the underlying object attributes. No changes would be |
299 | required to the template as the template processor would realise |
300 | that it needed to call methods rather than access hash values. |
301 | .Sh "A more complex example" |
302 | .IX Subsection "A more complex example" |
303 | Stats about the English Football League are usually presented in |
304 | a slightly more complex format than the one we used above. A |
305 | full set of stats will show the number of games that a team has |
306 | won, lost or drawn, the number of goals scored for and against |
307 | the team and the number of points that the team therefore has. |
308 | Teams gain three points for a win and one point for a draw. When |
309 | teams have the same number of points they are separated by the |
310 | goal difference, that is the number of goals the team has scored |
311 | minus the number of team scored against them. To complicate |
312 | things even further, the games won, drawn and lost and the goals |
313 | for and against are often split between home and away games. |
314 | .PP |
315 | Therefore if you have a data source which lists the team name |
316 | togther with the games won, drawn and lost and the goals for and |
317 | against split into home and away (a total of eleven data items) |
318 | you can calculate all of the other items (goal difference, |
319 | points awarded and even position in the league). Let's take such |
320 | a file, but we'll only look at the top three teams. It will look |
321 | something like this: |
322 | .PP |
323 | .Vb 3 |
324 | \& Man Utd,7,1,0,26,4,5,2,1,15,6 |
325 | \& Arsenal,7,1,0,17,4,2,3,3,7,9 |
326 | \& Leicester,4,3,1,10,8,4,2,2,7,4 |
327 | .Ve |
328 | .PP |
329 | A simple script to read this data into an array of hashes will |
330 | look something like this (I've simplified the names of the data |
331 | columns \- w, d, and l are games won, drawn and lost and f and a |
332 | are goals scored for and against; h and a at the front of a data |
333 | item name indicates whether it's a home or away statistic): |
334 | .PP |
335 | .Vb 1 |
336 | \& my @cols = qw(name hw hd hl hf ha aw ad al af aa); |
337 | .Ve |
338 | .PP |
339 | .Vb 3 |
340 | \& my @teams; |
341 | \& while (<>) { |
342 | \& chomp; |
343 | .Ve |
344 | .PP |
345 | .Vb 1 |
346 | \& my %team; |
347 | .Ve |
348 | .PP |
349 | .Vb 1 |
350 | \& @team{@cols} = split /,/; |
351 | .Ve |
352 | .PP |
353 | .Vb 2 |
354 | \& push @teams, \e%team; |
355 | \& } |
356 | .Ve |
357 | .PP |
358 | We can then go thru the teams again and calculate all of the |
359 | derived data items: |
360 | .PP |
361 | .Vb 4 |
362 | \& foreach (@teams) { |
363 | \& $_\->{w} = $_\->{hw} + $_\->{aw}; |
364 | \& $_\->{d} = $_\->{hd} + $_\->{ad}; |
365 | \& $_\->{l} = $_\->{hl} + $_\->{al}; |
366 | .Ve |
367 | .PP |
368 | .Vb 1 |
369 | \& $_\->{pl} = $_\->{w} + $_\->{d} + $_\->{l}; |
370 | .Ve |
371 | .PP |
372 | .Vb 2 |
373 | \& $_\->{f} = $_\->{hf} + $_\->{af}; |
374 | \& $_\->{a} = $_\->{ha} + $_\->{aa}; |
375 | .Ve |
376 | .PP |
377 | .Vb 3 |
378 | \& $_\->{gd} = $_\->{f} \- $_\->{a}; |
379 | \& $_\->{pt} = (3 * $_\->{w}) + $_\->{d}; |
380 | \& } |
381 | .Ve |
382 | .PP |
383 | And then produce a list sorted in descending order: |
384 | .PP |
385 | .Vb 3 |
386 | \& @teams = sort { |
387 | \& $b\->{pt} <=> $b\->{pt} || $b\->{gd} <=> $a\->{gd} |
388 | \& } @teams; |
389 | .Ve |
390 | .PP |
391 | And finally add the league position data item: |
392 | .PP |
393 | .Vb 2 |
394 | \& $teams[$_]\->{pos} = $_ + 1 |
395 | \& foreach 0 .. $#teams; |
396 | .Ve |
397 | .PP |
398 | Having pulled all of our data into an internal data structure |
399 | we can start to produce output using out templates. A template |
400 | to create a \s-1CSV\s0 file containing the data split between home and |
401 | away stats would look like this: |
402 | .PP |
403 | .Vb 6 |
404 | \& [% FOREACH team = teams \-%] |
405 | \& [% team.pos %],[% team.name %],[% team.pl %],[% team.hw %], |
406 | \& [%\- team.hd %],[% team.hl %],[% team.hf %],[% team.ha %], |
407 | \& [%\- team.aw %],[% team.ad %],[% team.al %],[% team.af %], |
408 | \& [%\- team.aa %],[% team.gd %],[% team.pt %] |
409 | \& [%\- END %] |
410 | .Ve |
411 | .PP |
412 | And processing it like this: |
413 | .PP |
414 | .Vb 2 |
415 | \& $tt\->process('split.tt', { teams => \e@teams }, 'split.csv') |
416 | \& || die $tt\->error; |
417 | .Ve |
418 | .PP |
419 | produces the following output: |
420 | .PP |
421 | .Vb 3 |
422 | \& 1,Man Utd,16,7,1,0,26,4,5,2,1,15,6,31,39 |
423 | \& 2,Arsenal,16,7,1,0,17,4,2,3,3,7,9,11,31 |
424 | \& 3,Leicester,16,4,3,1,10,8,4,2,2,7,4,5,29 |
425 | .Ve |
426 | .PP |
427 | Notice that we've introduced the third parameter to \f(CW\*(C`process\*(C'\fR. |
428 | If this parameter is missing then the \s-1TT2\s0 sends its output to |
429 | \&\f(CW\*(C`STDOUT\*(C'\fR. If this parameter is a scalar then it is taken as the |
430 | name of a file to write the output to. This parameter can also be |
431 | (amongst other things) a filehandle or a reference to an object w |
432 | hich is assumed to implement a \f(CW\*(C`print\*(C'\fR method. |
433 | .PP |
434 | If we weren't interested in the split between home and away games, |
435 | then we could use a simpler template like this: |
436 | .PP |
437 | .Vb 5 |
438 | \& [% FOREACH team = teams \-%] |
439 | \& [% team.pos %],[% team.name %],[% team.pl %],[% team.w %], |
440 | \& [%\- team.d %],[% team.l %],[% team.f %],[% team.a %], |
441 | \& [%\- team.aa %],[% team.gd %],[% team.pt %] |
442 | \& [% END \-%] |
443 | .Ve |
444 | .PP |
445 | Which would produce output like this: |
446 | .PP |
447 | .Vb 3 |
448 | \& 1,Man Utd,16,12,3,1,41,10,6,31,39 |
449 | \& 2,Arsenal,16,9,4,3,24,13,9,11,31 |
450 | \& 3,Leicester,16,8,5,3,17,12,4,5,29 |
451 | .Ve |
452 | .SH "Producing XML" |
453 | .IX Header "Producing XML" |
454 | This is starting to show some of the power and flexibility of |
455 | \&\s-1TT2\s0, but you may be thinking that you could just as easily produce |
456 | this output with a \f(CW\*(C`foreach\*(C'\fR loop and a couple of \f(CW\*(C`print\*(C'\fR |
457 | statements in your code. This is, of course, true; but that's |
458 | because I've chosen a deliberately simple example to explain the |
459 | concepts. What if we wanted to produce an \s-1XML\s0 file containing the |
460 | data? And what if (as I mentioned earlier) the league data was held |
461 | in an object? The code would then look even easier as most of the code |
462 | we've written earlier would be hidden away in \f(CW\*(C`FootballLeague.pm\*(C'\fR. |
463 | .PP |
464 | .Vb 2 |
465 | \& use FootballLeague; |
466 | \& use Template; |
467 | .Ve |
468 | .PP |
469 | .Vb 1 |
470 | \& my $league = FootballLeague\->new(name => 'English Premier'); |
471 | .Ve |
472 | .PP |
473 | .Vb 1 |
474 | \& my $tt = Template\->new; |
475 | .Ve |
476 | .PP |
477 | .Vb 2 |
478 | \& $tt\->process('league_xml.tt', { league => $league }) |
479 | \& || die $tt\->error; |
480 | .Ve |
481 | .PP |
482 | And the template in \f(CW\*(C`league_xml.tt\*(C'\fR would look something like this: |
483 | .PP |
484 | .Vb 2 |
485 | \& <?xml version="1.0"?> |
486 | \& <!DOCTYPE LEAGUE SYSTEM "league.dtd"> |
487 | .Ve |
488 | .PP |
489 | .Vb 22 |
490 | \& <league name="[% league.name %]" season="[% league.season %]"> |
491 | \& [% FOREACH team = league.teams \-%] |
492 | \& <team name="[% team.name %]" |
493 | \& pos="[% team.pos %]" |
494 | \& played="[% team.pl %]" |
495 | \& goal_diff="[% team.gd %]" |
496 | \& points="[% team.pt %]"> |
497 | \& <stats type="home"> |
498 | \& win="[% team.hw %]" |
499 | \& draw="[%\- team.hd %]" |
500 | \& lose="[% team.hl %]" |
501 | \& for="[% team.hf %]" |
502 | \& against="[% team.ha %]" /> |
503 | \& <stats type="away"> |
504 | \& win="[% team.aw %]" |
505 | \& draw="[%\- team.ad %]" |
506 | \& lose="[% team.al %]" |
507 | \& for="[% team.af %]" |
508 | \& against="[% team.aa %]" /> |
509 | \& </team> |
510 | \& [% END \-%] |
511 | \& &/league> |
512 | .Ve |
513 | .PP |
514 | Notice that as we've passed the whole object into \f(CW\*(C`process\*(C'\fR then |
515 | we need to put an extra level of indirection on our template |
516 | variables \- everything is now a component of the \f(CW\*(C`league\*(C'\fR variable. |
517 | Other than that, everything in the template is very similar to what |
518 | we've used before. Presumably now \f(CW\*(C`team.name\*(C'\fR calls an accessor |
519 | function rather than carrying out a hash lookup, but all of this |
520 | is transparent to our template designer. |
521 | .SH "Multiple Formats" |
522 | .IX Header "Multiple Formats" |
523 | As a final example, let's suppose that we need to create output |
524 | football league tables in a number of formats. Perhaps we are |
525 | passing this data on to other people and they can't all use the |
526 | same format. Some of our users need \s-1CSV\s0 files and others need |
527 | \&\s-1XML\s0. Some require data split between home and away matches and |
528 | other just want the totals. In total, then, we'll need four |
529 | different templates, but the good news is that they can use the |
530 | same data object. All the script needs to do is to establish |
531 | which template is required and process it. |
532 | .PP |
533 | .Vb 2 |
534 | \& use FootballLeague; |
535 | \& use Template; |
536 | .Ve |
537 | .PP |
538 | .Vb 1 |
539 | \& my ($name, $type, $stats) = @_; |
540 | .Ve |
541 | .PP |
542 | .Vb 1 |
543 | \& my $league = FootballLeague\->new(name => $name); |
544 | .Ve |
545 | .PP |
546 | .Vb 1 |
547 | \& my $tt = Template\->new; |
548 | .Ve |
549 | .PP |
550 | .Vb 4 |
551 | \& $tt\->process("league_${type}_$stats.tt", |
552 | \& { league => $league } |
553 | \& "league_$stats.$type") |
554 | \& || die $tt\->error; |
555 | .Ve |
556 | .PP |
557 | For example, you can call this script as |
558 | .PP |
559 | .Vb 1 |
560 | \& league.pl 'English Premier' xml split |
561 | .Ve |
562 | .PP |
563 | This will process a template called \f(CW\*(C`league_xml_split.tt\*(C'\fR |
564 | and put the results in a file called \f(CW\*(C`league_split.xml\*(C'\fR. |
565 | .PP |
566 | This starts to show the true strength of the Template Toolkit. |
567 | If we later wanted to add another file format \- perhaps we |
568 | wanted to create a league table \s-1HTML\s0 page or even a LaTeX |
569 | document \- then we would just need to create the appropriate |
570 | template and name it according to our existing naming |
571 | convention. We would need to make no changes to the code. |
572 | .PP |
573 | I hope you can now see why the Template Toolkit is fast becoming |
574 | an essential part of many people's Perl installation. |
575 | .SH "AUTHOR" |
576 | .IX Header "AUTHOR" |
577 | Dave Cross <dave@dave.org.uk> |
578 | .SH "VERSION" |
579 | .IX Header "VERSION" |
580 | Template Toolkit version 2.19, released on 27 April 2007. |
581 | .SH "COPYRIGHT" |
582 | .IX Header "COPYRIGHT" |
583 | Copyright (C) 2001 Dave Cross <dave@dave.org.uk> |
584 | .PP |
585 | This module is free software; you can redistribute it and/or |
586 | modify it under the same terms as Perl itself. |