File Coverage

blib/lib/Excel/Writer/XLSX/Package/XMLwriter.pm
Criterion Covered Total %
statement 178 189 94.1
branch 7 8 87.5
condition n/a
subroutine 25 26 96.1
pod 0 17 0.0
total 210 240 87.5


line stmt bran cond sub pod time code
1             package Excel::Writer::XLSX::Package::XMLwriter;
2              
3             ###############################################################################
4             #
5             # XMLwriter - A base class for the Excel::Writer::XLSX writer classes.
6             #
7             # Used in conjunction with Excel::Writer::XLSX
8             #
9             # Copyright 2000-2019, John McNamara, jmcnamara@cpan.org
10             #
11             # Documentation after __END__
12             #
13              
14             # perltidy with the following options: -mbl=2 -pt=0 -nola
15              
16 1041     1041   17236 use 5.008002;
  1041         3836  
17 1041     1041   5783 use strict;
  1041         2340  
  1041         22735  
18 1041     1041   5501 use warnings;
  1041         2348  
  1041         26820  
19 1041     1041   5746 use Exporter;
  1041         2440  
  1041         38837  
20 1041     1041   6547 use Carp;
  1041         2508  
  1041         56436  
21 1041     1041   7294 use IO::File;
  1041         3398  
  1041         2016754  
22              
23             our @ISA = qw(Exporter);
24             our $VERSION = '1.03';
25              
26             #
27             # NOTE: this module is a light weight re-implementation of XML::Writer. See
28             # the Pod docs below for a full explanation. The methods are implemented
29             # for speed rather than readability since they are used heavily in tight
30             # loops by Excel::Writer::XLSX.
31             #
32              
33             # Note "local $\ = undef" protect print statements from -l on commandline.
34              
35              
36             ###############################################################################
37             #
38             # new()
39             #
40             # Constructor.
41             #
42             sub new {
43              
44 11861     11861 0 25171 my $class = shift;
45              
46             # FH may be undef and set later in _set_xml_writer(), see below.
47 11861         20672 my $fh = shift;
48              
49 11861         31204 my $self = { _fh => $fh };
50              
51 11861         26348 bless $self, $class;
52              
53 11861         31025 return $self;
54             }
55              
56              
57             ###############################################################################
58             #
59             # _set_xml_writer()
60             #
61             # Set the XML writer filehandle for the object. This can either be done
62             # in the constructor (usually for testing since the file name isn't generally
63             # known at that stage) or later via this method.
64             #
65             sub _set_xml_writer {
66              
67 8950     8950   108026 my $self = shift;
68 8950         14997 my $filename = shift;
69              
70 8950         46487 my $fh = IO::File->new( $filename, 'w' );
71 8950 50       1072672 croak "Couldn't open file $filename for writing.\n" unless $fh;
72              
73 8950         47133 binmode $fh, ':utf8';
74              
75 8950         35579 $self->{_fh} = $fh;
76             }
77              
78              
79             ###############################################################################
80             #
81             # xml_declaration()
82             #
83             # Write the XML declaration.
84             #
85             sub xml_declaration {
86              
87 8995     8995 0 17672 my $self = shift;
88 8995         31430 local $\ = undef;
89              
90 8995         15611 print { $self->{_fh} }
  8995         149582  
91             qq(\n);
92              
93             }
94              
95              
96             ###############################################################################
97             #
98             # xml_start_tag()
99             #
100             # Write an XML start tag with optional attributes.
101             #
102             sub xml_start_tag {
103              
104 81712     81712 0 127340 my $self = shift;
105 81712         123551 my $tag = shift;
106              
107 81712         169599 while ( @_ ) {
108 77610         117582 my $key = shift @_;
109 77610         110762 my $value = shift @_;
110 77610         130117 $value = _escape_attributes( $value );
111              
112 77610         216475 $tag .= qq( $key="$value");
113             }
114              
115 81712         188231 local $\ = undef;
116 81712         117690 print { $self->{_fh} } "<$tag>";
  81712         301409  
117             }
118              
119              
120             ###############################################################################
121             #
122             # xml_start_tag_unencoded()
123             #
124             # Write an XML start tag with optional, unencoded, attributes.
125             # This is a minor speed optimisation for elements that don't need encoding.
126             #
127             sub xml_start_tag_unencoded {
128              
129 3913     3913 0 6982 my $self = shift;
130 3913         6677 my $tag = shift;
131              
132 3913         9740 while ( @_ ) {
133 7969         12486 my $key = shift @_;
134 7969         12173 my $value = shift @_;
135              
136 7969         21069 $tag .= qq( $key="$value");
137             }
138              
139 3913         10260 local $\ = undef;
140 3913         6325 print { $self->{_fh} } "<$tag>";
  3913         18198  
141             }
142              
143              
144             ###############################################################################
145             #
146             # xml_end_tag()
147             #
148             # Write an XML end tag.
149             #
150             sub xml_end_tag {
151              
152 85613     85613 0 136149 my $self = shift;
153 85613         128575 my $tag = shift;
154 85613         172653 local $\ = undef;
155              
156 85613         120236 print { $self->{_fh} } "";
  85613         304318  
157             }
158              
159              
160             ###############################################################################
161             #
162             # xml_empty_tag()
163             #
164             # Write an empty XML tag with optional attributes.
165             #
166             sub xml_empty_tag {
167              
168 100188     100188 0 158977 my $self = shift;
169 100188         148630 my $tag = shift;
170              
171 100188         200193 while ( @_ ) {
172 146718         217298 my $key = shift @_;
173 146718         209892 my $value = shift @_;
174 146718         234666 $value = _escape_attributes( $value );
175              
176 146718         397356 $tag .= qq( $key="$value");
177             }
178              
179 100188         230285 local $\ = undef;
180              
181 100188         140616 print { $self->{_fh} } "<$tag/>";
  100188         388324  
182             }
183              
184              
185             ###############################################################################
186             #
187             # xml_empty_tag_unencoded()
188             #
189             # Write an empty XML tag with optional, unencoded, attributes.
190             # This is a minor speed optimisation for elements that don't need encoding.
191             #
192             sub xml_empty_tag_unencoded {
193              
194 367     367 0 613 my $self = shift;
195 367         598 my $tag = shift;
196              
197 367         835 while ( @_ ) {
198 817         1246 my $key = shift @_;
199 817         1220 my $value = shift @_;
200              
201 817         1987 $tag .= qq( $key="$value");
202             }
203              
204 367         969 local $\ = undef;
205              
206 367         545 print { $self->{_fh} } "<$tag/>";
  367         1882  
207             }
208              
209              
210             ###############################################################################
211             #
212             # xml_data_element()
213             #
214             # Write an XML element containing data with optional attributes.
215             # XML characters in the data are encoded.
216             #
217             sub xml_data_element {
218              
219 46516     46516 0 72322 my $self = shift;
220 46516         68992 my $tag = shift;
221 46516         68127 my $data = shift;
222 46516         66263 my $end_tag = $tag;
223              
224 46516         94700 while ( @_ ) {
225 1856         4758 my $key = shift @_;
226 1856         4111 my $value = shift @_;
227 1856         5732 $value = _escape_attributes( $value );
228              
229 1856         8194 $tag .= qq( $key="$value");
230             }
231              
232 46516         78931 $data = _escape_data( $data );
233              
234 46516         110038 local $\ = undef;
235 46516         67021 print { $self->{_fh} } "<$tag>$data";
  46516         180291  
236             }
237              
238              
239             ###############################################################################
240             #
241             # xml_data_element_unencoded()
242             #
243             # Write an XML unencoded element containing data with optional attributes.
244             # This is a minor speed optimisation for elements that don't need encoding.
245             #
246             sub xml_data_element_unencoded {
247              
248 0     0 0 0 my $self = shift;
249 0         0 my $tag = shift;
250 0         0 my $data = shift;
251 0         0 my $end_tag = $tag;
252              
253 0         0 while ( @_ ) {
254 0         0 my $key = shift @_;
255 0         0 my $value = shift @_;
256              
257 0         0 $tag .= qq( $key="$value");
258             }
259              
260 0         0 local $\ = undef;
261 0         0 print { $self->{_fh} } "<$tag>$data";
  0         0  
262             }
263              
264              
265             ###############################################################################
266             #
267             # xml_string_element()
268             #
269             # Optimised tag writer for cell string elements in the inner loop.
270             #
271             sub xml_string_element {
272              
273 2642     2642 0 4348 my $self = shift;
274 2642         3847 my $index = shift;
275 2642         3973 my $attr = '';
276              
277 2642         5605 while ( @_ ) {
278 2803         4190 my $key = shift;
279 2803         4213 my $value = shift;
280 2803         7402 $attr .= qq( $key="$value");
281             }
282              
283 2642         6520 local $\ = undef;
284 2642         3934 print { $self->{_fh} } "$index";
  2642         14997  
285             }
286              
287              
288             ###############################################################################
289             #
290             # xml_si_element()
291             #
292             # Optimised tag writer for shared strings elements.
293             #
294             sub xml_si_element {
295              
296 1041     1041 0 2274 my $self = shift;
297 1041         1719 my $string = shift;
298 1041         1705 my $attr = '';
299              
300              
301 1041         2626 while ( @_ ) {
302 6         11 my $key = shift;
303 6         13 my $value = shift;
304 6         31 $attr .= qq( $key="$value");
305             }
306              
307 1041         2279 $string = _escape_data( $string );
308              
309 1041         2914 local $\ = undef;
310 1041         1704 print { $self->{_fh} } "$string";
  1041         5491  
311             }
312              
313              
314             ###############################################################################
315             #
316             # xml_rich_si_element()
317             #
318             # Optimised tag writer for shared strings rich string elements.
319             #
320             sub xml_rich_si_element {
321              
322 17     17 0 46 my $self = shift;
323 17         39 my $string = shift;
324              
325              
326 17         53 local $\ = undef;
327 17         66 print { $self->{_fh} } "$string";
  17         194  
328             }
329              
330              
331             ###############################################################################
332             #
333             # xml_number_element()
334             #
335             # Optimised tag writer for cell number elements in the inner loop.
336             #
337             sub xml_number_element {
338              
339 7025     7025 0 11087 my $self = shift;
340 7025         10484 my $number = shift;
341 7025         10411 my $attr = '';
342              
343 7025         14519 while ( @_ ) {
344 7208         10516 my $key = shift;
345 7208         10219 my $value = shift;
346 7208         18080 $attr .= qq( $key="$value");
347             }
348              
349 7025         16180 local $\ = undef;
350 7025         10202 print { $self->{_fh} } "$number";
  7025         37445  
351             }
352              
353              
354             ###############################################################################
355             #
356             # xml_formula_element()
357             #
358             # Optimised tag writer for cell formula elements in the inner loop.
359             #
360             sub xml_formula_element {
361              
362 75     75 0 170 my $self = shift;
363 75         128 my $formula = shift;
364 75         152 my $result = shift;
365 75         197 my $attr = '';
366              
367 75         220 while ( @_ ) {
368 111         191 my $key = shift;
369 111         182 my $value = shift;
370 111         344 $attr .= qq( $key="$value");
371             }
372              
373 75         223 $formula = _escape_data( $formula );
374              
375 75         232 local $\ = undef;
376 75         125 print { $self->{_fh} } "$formula$result";
  75         597  
377             }
378              
379              
380             ###############################################################################
381             #
382             # xml_inline_string()
383             #
384             # Optimised tag writer for inlineStr cell elements in the inner loop.
385             #
386             sub xml_inline_string {
387              
388 290     290 0 460 my $self = shift;
389 290         441 my $string = shift;
390 290         401 my $preserve = shift;
391 290         432 my $attr = '';
392 290         417 my $t_attr = '';
393              
394             # Set the attribute to preserve whitespace.
395 290 100       526 $t_attr = ' xml:space="preserve"' if $preserve;
396              
397 290         585 while ( @_ ) {
398 307         447 my $key = shift;
399 307         447 my $value = shift;
400 307         803 $attr .= qq( $key="$value");
401             }
402              
403 290         558 $string = _escape_data( $string );
404              
405 290         790 local $\ = undef;
406 290         462 print { $self->{_fh} }
  290         1957  
407             "$string";
408             }
409              
410              
411             ###############################################################################
412             #
413             # xml_rich_inline_string()
414             #
415             # Optimised tag writer for rich inlineStr cell elements in the inner loop.
416             #
417             sub xml_rich_inline_string {
418              
419 8     8 0 18 my $self = shift;
420 8         21 my $string = shift;
421 8         16 my $attr = '';
422              
423 8         23 while ( @_ ) {
424 8         14 my $key = shift;
425 8         16 my $value = shift;
426 8         28 $attr .= qq( $key="$value");
427             }
428              
429 8         32 local $\ = undef;
430 8         16 print { $self->{_fh} } "$string";
  8         77  
431             }
432              
433              
434             ###############################################################################
435             #
436             # xml_get_fh()
437             #
438             # Return the output filehandle.
439             #
440             sub xml_get_fh {
441              
442 9060     9060 0 18650 my $self = shift;
443              
444 9060         41644 return $self->{_fh};
445             }
446              
447              
448             ###############################################################################
449             #
450             # _escape_attributes()
451             #
452             # Escape XML characters in attributes.
453             #
454             sub _escape_attributes {
455              
456 226184     226184   324852 my $str = $_[0];
457              
458 226184 100       643160 return $str if $str !~ m/["&<>\n]/;
459              
460 14         41 for ( $str ) {
461 14         54 s/&/&/g;
462 14         57 s/"/"/g;
463 14         41 s/
464 14         40 s/>/>/g;
465 14         41 s/\n/ /g;
466             }
467              
468 14         48 return $str;
469             }
470              
471              
472             ###############################################################################
473             #
474             # _escape_data()
475             #
476             # Escape XML characters in data sections. Note, this is different from
477             # _escape_attributes() in that double quotes are not escaped by Excel.
478             #
479             sub _escape_data {
480              
481 47929     47929   72117 my $str = $_[0];
482              
483 47929 100       135339 return $str if $str !~ m/[&<>]/;
484              
485 87         242 for ( $str ) {
486 87         359 s/&/&/g;
487 87         284 s/
488 87         275 s/>/>/g;
489             }
490              
491 87         240 return $str;
492             }
493              
494              
495             1;
496              
497              
498             __END__