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-2020, 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 1082     1082   16711 use 5.008002;
  1082         3486  
17 1082     1082   5935 use strict;
  1082         2220  
  1082         23968  
18 1082     1082   5531 use warnings;
  1082         2318  
  1082         33398  
19 1082     1082   5894 use Exporter;
  1082         2513  
  1082         37692  
20 1082     1082   6248 use Carp;
  1082         2365  
  1082         54346  
21 1082     1082   7134 use IO::File;
  1082         3143  
  1082         1939797  
22              
23             our @ISA = qw(Exporter);
24             our $VERSION = '1.07';
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 12440     12440 0 23914 my $class = shift;
45              
46             # FH may be undef and set later in _set_xml_writer(), see below.
47 12440         19422 my $fh = shift;
48              
49 12440         29993 my $self = { _fh => $fh };
50              
51 12440         24527 bless $self, $class;
52              
53 12440         29284 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 9411     9411   103018 my $self = shift;
68 9411         14548 my $filename = shift;
69              
70 9411         45993 my $fh = IO::File->new( $filename, 'w' );
71 9411 50       1135748 croak "Couldn't open file $filename for writing.\n" unless $fh;
72              
73 9411         46854 binmode $fh, ':utf8';
74              
75 9411         34322 $self->{_fh} = $fh;
76             }
77              
78              
79             ###############################################################################
80             #
81             # xml_declaration()
82             #
83             # Write the XML declaration.
84             #
85             sub xml_declaration {
86              
87 9452     9452 0 16216 my $self = shift;
88 9452         30736 local $\ = undef;
89              
90 9452         14831 print { $self->{_fh} }
  9452         148102  
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 84422     84422 0 115201 my $self = shift;
105 84422         111242 my $tag = shift;
106              
107 84422         154307 while ( @_ ) {
108 79397         102900 my $key = shift @_;
109 79397         100109 my $value = shift @_;
110 79397         114428 $value = _escape_attributes( $value );
111              
112 79397         194141 $tag .= qq( $key="$value");
113             }
114              
115 84422         175044 local $\ = undef;
116 84422         105709 print { $self->{_fh} } "<$tag>";
  84422         282728  
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 4045     4045 0 6777 my $self = shift;
130 4045         6107 my $tag = shift;
131              
132 4045         8643 while ( @_ ) {
133 8229         12128 my $key = shift @_;
134 8229         11205 my $value = shift @_;
135              
136 8229         20285 $tag .= qq( $key="$value");
137             }
138              
139 4045         10260 local $\ = undef;
140 4045         5848 print { $self->{_fh} } "<$tag>";
  4045         17939  
141             }
142              
143              
144             ###############################################################################
145             #
146             # xml_end_tag()
147             #
148             # Write an XML end tag.
149             #
150             sub xml_end_tag {
151              
152 88455     88455 0 124318 my $self = shift;
153 88455         113625 my $tag = shift;
154 88455         156652 local $\ = undef;
155              
156 88455         107788 print { $self->{_fh} } "";
  88455         280162  
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 103452     103452 0 144229 my $self = shift;
169 103452         136508 my $tag = shift;
170              
171 103452         180210 while ( @_ ) {
172 151970         197296 my $key = shift @_;
173 151970         192087 my $value = shift @_;
174 151970         213709 $value = _escape_attributes( $value );
175              
176 151970         376099 $tag .= qq( $key="$value");
177             }
178              
179 103452         213301 local $\ = undef;
180              
181 103452         127695 print { $self->{_fh} } "<$tag/>";
  103452         359216  
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 369     369 0 562 my $self = shift;
195 369         511 my $tag = shift;
196              
197 369         783 while ( @_ ) {
198 821         1119 my $key = shift @_;
199 821         1028 my $value = shift @_;
200              
201 821         1822 $tag .= qq( $key="$value");
202             }
203              
204 369         958 local $\ = undef;
205              
206 369         495 print { $self->{_fh} } "<$tag/>";
  369         1699  
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 47956     47956 0 65204 my $self = shift;
220 47956         60678 my $tag = shift;
221 47956         60659 my $data = shift;
222 47956         59399 my $end_tag = $tag;
223              
224 47956         86377 while ( @_ ) {
225 1938         4328 my $key = shift @_;
226 1938         4326 my $value = shift @_;
227 1938         5330 $value = _escape_attributes( $value );
228              
229 1938         8156 $tag .= qq( $key="$value");
230             }
231              
232 47956         72103 $data = _escape_data( $data );
233              
234 47956         100550 local $\ = undef;
235 47956         60284 print { $self->{_fh} } "<$tag>$data";
  47956         164527  
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 2648     2648 0 3825 my $self = shift;
274 2648         3413 my $index = shift;
275 2648         3507 my $attr = '';
276              
277 2648         4798 while ( @_ ) {
278 2810         3729 my $key = shift;
279 2810         3834 my $value = shift;
280 2810         6746 $attr .= qq( $key="$value");
281             }
282              
283 2648         6208 local $\ = undef;
284 2648         3430 print { $self->{_fh} } "$index";
  2648         13597  
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 1047     1047 0 2066 my $self = shift;
297 1047         1647 my $string = shift;
298 1047         1589 my $attr = '';
299              
300              
301 1047         2547 while ( @_ ) {
302 6         12 my $key = shift;
303 6         10 my $value = shift;
304 6         20 $attr .= qq( $key="$value");
305             }
306              
307 1047         2445 $string = _escape_data( $string );
308              
309 1047         2699 local $\ = undef;
310 1047         1554 print { $self->{_fh} } "$string";
  1047         5053  
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 49 my $self = shift;
323 17         35 my $string = shift;
324              
325              
326 17         48 local $\ = undef;
327 17         36 print { $self->{_fh} } "$string";
  17         183  
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 7438     7438 0 10681 my $self = shift;
340 7438         9847 my $number = shift;
341 7438         9915 my $attr = '';
342              
343 7438         13753 while ( @_ ) {
344 7621         10106 my $key = shift;
345 7621         9903 my $value = shift;
346 7621         17506 $attr .= qq( $key="$value");
347             }
348              
349 7438         16001 local $\ = undef;
350 7438         9618 print { $self->{_fh} } "$number";
  7438         36451  
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 159 my $self = shift;
363 75         112 my $formula = shift;
364 75         115 my $result = shift;
365 75         107 my $attr = '';
366              
367 75         168 while ( @_ ) {
368 111         1140 my $key = shift;
369 111         169 my $value = shift;
370 111         290 $attr .= qq( $key="$value");
371             }
372              
373 75         187 $formula = _escape_data( $formula );
374              
375 75         225 local $\ = undef;
376 75         118 print { $self->{_fh} } "$formula$result";
  75         529  
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 294     294 0 411 my $self = shift;
389 294         450 my $string = shift;
390 294         342 my $preserve = shift;
391 294         369 my $attr = '';
392 294         348 my $t_attr = '';
393              
394             # Set the attribute to preserve whitespace.
395 294 100       498 $t_attr = ' xml:space="preserve"' if $preserve;
396              
397 294         529 while ( @_ ) {
398 311         404 my $key = shift;
399 311         398 my $value = shift;
400 311         680 $attr .= qq( $key="$value");
401             }
402              
403 294         485 $string = _escape_data( $string );
404              
405 294         746 local $\ = undef;
406 294         411 print { $self->{_fh} }
  294         1754  
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 15 my $self = shift;
420 8         13 my $string = shift;
421 8         14 my $attr = '';
422              
423 8         24 while ( @_ ) {
424 8         12 my $key = shift;
425 8         22 my $value = shift;
426 8         27 $attr .= qq( $key="$value");
427             }
428              
429 8         24 local $\ = undef;
430 8         23 print { $self->{_fh} } "$string";
  8         82  
431             }
432              
433              
434             ###############################################################################
435             #
436             # xml_get_fh()
437             #
438             # Return the output filehandle.
439             #
440             sub xml_get_fh {
441              
442 9523     9523 0 17798 my $self = shift;
443              
444 9523         42015 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 233305     233305   300332 my $str = $_[0];
457              
458 233305 100       593429 return $str if $str !~ m/["&<>\n]/;
459              
460 14         34 for ( $str ) {
461 14         71 s/&/&/g;
462 14         38 s/"/"/g;
463 14         39 s/
464 14         28 s/>/>/g;
465 14         39 s/\n/ /g;
466             }
467              
468 14         40 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 49379     49379   63629 my $str = $_[0];
482              
483 49379 100       122641 return $str if $str !~ m/[&<>]/;
484              
485 87         220 for ( $str ) {
486 87         309 s/&/&/g;
487 87         248 s/
488 87         233 s/>/>/g;
489             }
490              
491 87         216 return $str;
492             }
493              
494              
495             1;
496              
497              
498             __END__