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              
2             ###############################################################################
3             #
4             # XMLwriter - A base class for the Excel::Writer::XLSX writer classes.
5             #
6             # Used in conjunction with Excel::Writer::XLSX
7             #
8             # Copyright 2000-2021, John McNamara, jmcnamara@cpan.org
9             #
10             # Documentation after __END__
11             #
12              
13             # perltidy with the following options: -mbl=2 -pt=0 -nola
14              
15             use 5.008002;
16 1126     1126   14774 use strict;
  1126         3242  
17 1126     1126   4824 use warnings;
  1126         1949  
  1126         19801  
18 1126     1126   4898 use Exporter;
  1126         2107  
  1126         33716  
19 1126     1126   5852 use Carp;
  1126         2202  
  1126         34668  
20 1126     1126   5656 use IO::File;
  1126         2303  
  1126         49423  
21 1126     1126   6957  
  1126         3897  
  1126         1774160  
22             our @ISA = qw(Exporter);
23             our $VERSION = '1.09';
24              
25             #
26             # NOTE: this module is a light weight re-implementation of XML::Writer. See
27             # the Pod docs below for a full explanation. The methods are implemented
28             # for speed rather than readability since they are used heavily in tight
29             # loops by Excel::Writer::XLSX.
30             #
31              
32             # Note "local $\ = undef" protect print statements from -l on commandline.
33              
34              
35             ###############################################################################
36             #
37             # new()
38             #
39             # Constructor.
40             #
41              
42             my $class = shift;
43              
44 13889     13889 0 23031 # FH may be undef and set later in _set_xml_writer(), see below.
45             my $fh = shift;
46              
47 13889         19225 my $self = { _fh => $fh };
48              
49 13889         29671 bless $self, $class;
50              
51 13889         24740 return $self;
52             }
53 13889         29147  
54              
55             ###############################################################################
56             #
57             # _set_xml_writer()
58             #
59             # Set the XML writer filehandle for the object. This can either be done
60             # in the constructor (usually for testing since the file name isn't generally
61             # known at that stage) or later via this method.
62             #
63              
64             my $self = shift;
65             my $filename = shift;
66              
67 9850     9850   91548 my $fh = IO::File->new( $filename, 'w' );
68 9850         13207 croak "Couldn't open file $filename for writing.\n" unless $fh;
69              
70 9850         43108 binmode $fh, ':utf8';
71 9850 50       1018360  
72             $self->{_fh} = $fh;
73 9850         43448 }
74              
75 9850         30535  
76             ###############################################################################
77             #
78             # xml_declaration()
79             #
80             # Write the XML declaration.
81             #
82              
83             my $self = shift;
84             local $\ = undef;
85              
86             print { $self->{_fh} }
87 9888     9888 0 15083 qq(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n);
88 9888         27875  
89             }
90 9888         13908  
  9888         137965  
91              
92             ###############################################################################
93             #
94             # xml_start_tag()
95             #
96             # Write an XML start tag with optional attributes.
97             #
98              
99             my $self = shift;
100             my $tag = shift;
101              
102             while ( @_ ) {
103             my $key = shift @_;
104 86326     86326 0 106814 my $value = shift @_;
105 86326         101475 $value = _escape_attributes( $value );
106              
107 86326         143485 $tag .= qq( $key="$value");
108 80908         98080 }
109 80908         90222  
110 80908         105151 local $\ = undef;
111             print { $self->{_fh} } "<$tag>";
112 80908         178122 }
113              
114              
115 86326         159372 ###############################################################################
116 86326         95280 #
  86326         260912  
117             # xml_start_tag_unencoded()
118             #
119             # Write an XML start tag with optional, unencoded, attributes.
120             # This is a minor speed optimisation for elements that don't need encoding.
121             #
122              
123             my $self = shift;
124             my $tag = shift;
125              
126             while ( @_ ) {
127             my $key = shift @_;
128             my $value = shift @_;
129 4121     4121 0 5771  
130 4121         5321 $tag .= qq( $key="$value");
131             }
132 4121         7825  
133 8381         10368 local $\ = undef;
134 8381         9713 print { $self->{_fh} } "<$tag>";
135             }
136 8381         18116  
137              
138             ###############################################################################
139 4121         8572 #
140 4121         5520 # xml_end_tag()
  4121         15419  
141             #
142             # Write an XML end tag.
143             #
144              
145             my $self = shift;
146             my $tag = shift;
147             local $\ = undef;
148              
149             print { $self->{_fh} } "</$tag>";
150             }
151              
152 90435     90435 0 112776  
153 90435         105071 ###############################################################################
154 90435         142939 #
155             # xml_empty_tag()
156 90435         99246 #
  90435         254459  
157             # Write an empty XML tag with optional attributes.
158             #
159              
160             my $self = shift;
161             my $tag = shift;
162              
163             while ( @_ ) {
164             my $key = shift @_;
165             my $value = shift @_;
166             $value = _escape_attributes( $value );
167              
168 106034     106034 0 130177 $tag .= qq( $key="$value");
169 106034         123990 }
170              
171 106034         165822 local $\ = undef;
172 156746         183605  
173 156746         177279 print { $self->{_fh} } "<$tag/>";
174 156746         195699 }
175              
176 156746         335473  
177             ###############################################################################
178             #
179 106034         191966 # xml_empty_tag_unencoded()
180             #
181 106034         116468 # Write an empty XML tag with optional, unencoded, attributes.
  106034         328898  
182             # This is a minor speed optimisation for elements that don't need encoding.
183             #
184              
185             my $self = shift;
186             my $tag = shift;
187              
188             while ( @_ ) {
189             my $key = shift @_;
190             my $value = shift @_;
191              
192             $tag .= qq( $key="$value");
193             }
194 415     415 0 609  
195 415         506 local $\ = undef;
196              
197 415         1009 print { $self->{_fh} } "<$tag/>";
198 960         1148 }
199 960         1044  
200              
201 960         1963 ###############################################################################
202             #
203             # xml_data_element()
204 415         864 #
205             # Write an XML element containing data with optional attributes.
206 415         523 # XML characters in the data are encoded.
  415         1706  
207             #
208              
209             my $self = shift;
210             my $tag = shift;
211             my $data = shift;
212             my $end_tag = $tag;
213              
214             while ( @_ ) {
215             my $key = shift @_;
216             my $value = shift @_;
217             $value = _escape_attributes( $value );
218              
219 48953     48953 0 59731 $tag .= qq( $key="$value");
220 48953         55784 }
221 48953         55527  
222 48953         54787 $data = _escape_data( $data );
223              
224 48953         78549 local $\ = undef;
225 2026         3509 print { $self->{_fh} } "<$tag>$data</$end_tag>";
226 2026         3921 }
227 2026         4667  
228              
229 2026         6980 ###############################################################################
230             #
231             # xml_data_element_unencoded()
232 48953         64854 #
233             # Write an XML unencoded element containing data with optional attributes.
234 48953         89337 # This is a minor speed optimisation for elements that don't need encoding.
235 48953         54879 #
  48953         152582  
236              
237             my $self = shift;
238             my $tag = shift;
239             my $data = shift;
240             my $end_tag = $tag;
241              
242             while ( @_ ) {
243             my $key = shift @_;
244             my $value = shift @_;
245              
246             $tag .= qq( $key="$value");
247             }
248 0     0 0 0  
249 0         0 local $\ = undef;
250 0         0 print { $self->{_fh} } "<$tag>$data</$end_tag>";
251 0         0 }
252              
253 0         0  
254 0         0 ###############################################################################
255 0         0 #
256             # xml_string_element()
257 0         0 #
258             # Optimised tag writer for <c> cell string elements in the inner loop.
259             #
260 0         0  
261 0         0 my $self = shift;
  0         0  
262             my $index = shift;
263             my $attr = '';
264              
265             while ( @_ ) {
266             my $key = shift;
267             my $value = shift;
268             $attr .= qq( $key="$value");
269             }
270              
271             local $\ = undef;
272             print { $self->{_fh} } "<c$attr t=\"s\"><v>$index</v></c>";
273 2672     2672 0 3268 }
274 2672         3010  
275 2672         3070  
276             ###############################################################################
277 2672         4264 #
278 2836         3222 # xml_si_element()
279 2836         3278 #
280 2836         6100 # Optimised tag writer for shared strings <si> elements.
281             #
282              
283 2672         4869 my $self = shift;
284 2672         3519 my $string = shift;
  2672         11926  
285             my $attr = '';
286              
287              
288             while ( @_ ) {
289             my $key = shift;
290             my $value = shift;
291             $attr .= qq( $key="$value");
292             }
293              
294             $string = _escape_data( $string );
295              
296 1059     1059 0 1512 local $\ = undef;
297 1059         1451 print { $self->{_fh} } "<si><t$attr>$string</t></si>";
298 1059         1550 }
299              
300              
301 1059         2093 ###############################################################################
302 6         9 #
303 6         9 # xml_rich_si_element()
304 6         18 #
305             # Optimised tag writer for shared strings <si> rich string elements.
306             #
307 1059         2009  
308             my $self = shift;
309 1059         2302 my $string = shift;
310 1059         1534  
  1059         4345  
311              
312             local $\ = undef;
313             print { $self->{_fh} } "<si>$string</si>";
314             }
315              
316              
317             ###############################################################################
318             #
319             # xml_number_element()
320             #
321             # Optimised tag writer for <c> cell number elements in the inner loop.
322 17     17 0 43 #
323 17         38  
324             my $self = shift;
325             my $number = shift;
326 17         43 my $attr = '';
327 17         45  
  17         168  
328             while ( @_ ) {
329             my $key = shift;
330             my $value = shift;
331             $attr .= qq( $key="$value");
332             }
333              
334             local $\ = undef;
335             print { $self->{_fh} } "<c$attr><v>$number</v></c>";
336             }
337              
338              
339 7567     7567 0 9545 ###############################################################################
340 7567         8953 #
341 7567         9160 # xml_formula_element()
342             #
343 7567         12171 # Optimised tag writer for <c> cell formula elements in the inner loop.
344 7756         8933 #
345 7756         8829  
346 7756         15641 my $self = shift;
347             my $formula = shift;
348             my $result = shift;
349 7567         13634 my $attr = '';
350 7567         8483  
  7567         33854  
351             while ( @_ ) {
352             my $key = shift;
353             my $value = shift;
354             $attr .= qq( $key="$value");
355             }
356              
357             $formula = _escape_data( $formula );
358              
359             local $\ = undef;
360             print { $self->{_fh} } "<c$attr><f>$formula</f><v>$result</v></c>";
361             }
362 79     79 0 136  
363 79         117  
364 79         126 ###############################################################################
365 79         131 #
366             # xml_inline_string()
367 79         179 #
368 116         162 # Optimised tag writer for inlineStr cell elements in the inner loop.
369 116         165 #
370 116         292  
371             my $self = shift;
372             my $string = shift;
373 79         205 my $preserve = shift;
374             my $attr = '';
375 79         205 my $t_attr = '';
376 79         114  
  79         499  
377             # Set the <t> attribute to preserve whitespace.
378             $t_attr = ' xml:space="preserve"' if $preserve;
379              
380             while ( @_ ) {
381             my $key = shift;
382             my $value = shift;
383             $attr .= qq( $key="$value");
384             }
385              
386             $string = _escape_data( $string );
387              
388 294     294 0 336 local $\ = undef;
389 294         372 print { $self->{_fh} }
390 294         301 "<c$attr t=\"inlineStr\"><is><t$t_attr>$string</t></is></c>";
391 294         324 }
392 294         309  
393              
394             ###############################################################################
395 294 100       393 #
396             # xml_rich_inline_string()
397 294         439 #
398 311         323 # Optimised tag writer for rich inlineStr cell elements in the inner loop.
399 311         321 #
400 311         594  
401             my $self = shift;
402             my $string = shift;
403 294         439 my $attr = '';
404              
405 294         557 while ( @_ ) {
406 294         317 my $key = shift;
  294         1497  
407             my $value = shift;
408             $attr .= qq( $key="$value");
409             }
410              
411             local $\ = undef;
412             print { $self->{_fh} } "<c$attr t=\"inlineStr\"><is>$string</is></c>";
413             }
414              
415              
416             ###############################################################################
417             #
418             # xml_get_fh()
419 8     8 0 14 #
420 8         10 # Return the output filehandle.
421 8         10 #
422              
423 8         18 my $self = shift;
424 8         10  
425 8         10 return $self->{_fh};
426 8         21 }
427              
428              
429 8         28 ###############################################################################
430 8         10 #
  8         78  
431             # _escape_attributes()
432             #
433             # Escape XML characters in attributes.
434             #
435              
436             my $str = $_[0];
437              
438             return $str if $str !~ m/["&<>\n]/;
439              
440             for ( $str ) {
441             s/&/&amp;/g;
442 9962     9962 0 16495 s/"/&quot;/g;
443             s/</&lt;/g;
444 9962         37707 s/>/&gt;/g;
445             s/\n/&#xA;/g;
446             }
447              
448             return $str;
449             }
450              
451              
452             ###############################################################################
453             #
454             # _escape_data()
455             #
456 239680     239680   271469 # Escape XML characters in data sections. Note, this is different from
457             # _escape_attributes() in that double quotes are not escaped by Excel.
458 239680 100       537782 #
459              
460 14         38 my $str = $_[0];
461 14         46  
462 14         29 return $str if $str !~ m/[&<>]/;
463 14         36  
464 14         35 for ( $str ) {
465 14         34 s/&/&amp;/g;
466             s/</&lt;/g;
467             s/>/&gt;/g;
468 14         37 }
469              
470             return $str;
471             }
472              
473              
474             1;
475              
476              
477              
478             =pod
479              
480             =head1 NAME
481 50392     50392   59070  
482             XMLwriter - A base class for the Excel::Writer::XLSX writer classes.
483 50392 100       111823  
484             =head1 DESCRIPTION
485 90         232  
486 90         325 This module is used by L<Excel::Writer::XLSX> for writing XML documents. It is a light weight re-implementation of L<XML::Writer>.
487 90         201  
488 90         239 XMLwriter is approximately twice as fast as L<XML::Writer>. This speed is achieved at the expense of error and correctness checking. In addition not all of the L<XML::Writer> methods are implemented. As such, XMLwriter is not recommended for use outside of Excel::Writer::XLSX.
489              
490             =head1 SEE ALSO
491 90         328  
492             L<XML::Writer>.
493              
494             =head1 AUTHOR
495              
496             John McNamara jmcnamara@cpan.org
497              
498             =head1 COPYRIGHT
499              
500             (c) MM-MMXXI, John McNamara.
501              
502             All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
503              
504             =head1 LICENSE
505              
506             Either the Perl Artistic Licence L<http://dev.perl.org/licenses/artistic.html> or the GPL L<http://www.opensource.org/licenses/gpl-license.php>.
507              
508             =head1 DISCLAIMER OF WARRANTY
509              
510             See the documentation for L<Excel::Writer::XLSX>.
511              
512             =cut