File Coverage

blib/lib/XML/Writer.pm
Criterion Covered Total %
statement 638 638 100.0
branch 190 190 100.0
condition 102 108 94.4
subroutine 100 100 100.0
pod 27 27 100.0
total 1057 1063 99.4


line stmt bran cond sub pod time code
1             ########################################################################
2             # Writer.pm - write an XML document.
3             # Copyright (c) 1999 by Megginson Technologies.
4             # Copyright (c) 2003 Ed Avis
5             # Copyright (c) 2004-2010 Joseph Walton
6             # Redistribution and use in source and compiled forms, with or without
7             # modification, are permitted under any circumstances. No warranty.
8             ########################################################################
9              
10             package XML::Writer;
11              
12             require 5.004;
13              
14 2     2   51757 use strict;
  2         5  
  2         110  
15 2     2   9 use vars qw($VERSION);
  2         3  
  2         249  
16 2     2   20 use Carp;
  2         2  
  2         155  
17 2     2   1399 use IO::Handle;
  2         12889  
  2         131  
18             $VERSION = "0.625";
19              
20 2     2   3007 use overload '""' => \&_overload_string;
  2         1932  
  2         20  
21              
22            
23             ########################################################################
24             # Constructor.
25             ########################################################################
26              
27             #
28             # Public constructor.
29             #
30             # This actually does most of the work of the module: it defines closures
31             # for all of the real processing, and selects the appropriate closures
32             # to use based on the value of the UNSAFE parameter. The actual methods
33             # are just stubs.
34             #
35             sub new {
36 303     303 1 131631 my ($class, %params) = (@_);
37              
38             # If the user wants namespaces,
39             # intercept the request here; it will
40             # come back to this constructor
41             # from within XML::Writer::Namespaces::new()
42 303 100       1078 if ($params{NAMESPACES}) {
43 146         279 delete $params{NAMESPACES};
44 146         662 return XML::Writer::Namespaces->new(%params);
45             }
46              
47             # Set up $self and basic parameters
48 157         177 my $self;
49             my $output;
50 157         355 my $unsafe = $params{UNSAFE};
51 157         192 my $newlines = $params{NEWLINES};
52 157         175 my $dataMode = $params{DATA_MODE};
53 157         178 my $dataIndent;
54             my $selfcontained_output;
55 157         168 my $use_selfcontained_output = 0;
56              
57             # If the NEWLINES parameter is specified,
58             # set the $nl variable appropriately
59 157         198 my $nl = '';
60 157 100       279 if ($newlines) {
61 1         2 $nl = "\n";
62             }
63              
64 157   100     624 my $outputEncoding = $params{ENCODING} || "";
65 157         165 my ($checkUnencodedRepertoire, $escapeEncoding);
66 157 100       471 if (lc($outputEncoding) eq 'us-ascii') {
67 10         19 $checkUnencodedRepertoire = \&_croakUnlessASCII;
68 10         19 $escapeEncoding = \&_escapeASCII;
69             } else {
70 147     295   548 my $doNothing = sub {};
  295         339  
71 147         205 $checkUnencodedRepertoire = $doNothing;
72 147         205 $escapeEncoding = $doNothing;
73             }
74              
75             # Parse variables
76 157         438 my @elementStack = ();
77 157         174 my $elementLevel = 0;
78 157         667 my %seen = ();
79              
80 157         167 my $hasData = 0;
81 157         227 my @hasDataStack = ();
82 157         176 my $hasElement = 0;
83 157         182 my @hasElementStack = ();
84 157         302 my $hasHeading = 0; # Does this document have anything before the first element?
85              
86             #
87             # Private method to show attributes.
88             #
89             my $showAttributes = sub {
90 182     182   221 my $atts = $_[0];
91 182         206 my $i = 1;
92 182         518 while ($atts->[$i]) {
93 71         488 my $aname = $atts->[$i++];
94 71         369 my $value = _escapeLiteral($atts->[$i++]);
95 71         148 $value =~ s/\x0a/\ \;/g;
96 71         102 $value =~ s/\x0d/\ \;/g;
97 71         93 $value =~ s/\x09/\ \;/g;
98 71         77 &{$escapeEncoding}($value);
  71         139  
99 71         293 $output->print(" $aname=\"$value\"");
100             }
101 157         704 };
102              
103             # Method implementations: the SAFE_
104             # versions perform error checking
105             # and then call the regular ones.
106             my $end = sub {
107 87     87   211 $output->print("\n");
108              
109 87 100 100     561 return $selfcontained_output
110             if $use_selfcontained_output and defined wantarray;
111 157         524 };
112              
113             my $SAFE_end = sub {
114 80 100   80   229 if (!$seen{ELEMENT}) {
    100          
115 1         121 croak("Document cannot end without a document element");
116             } elsif ($elementLevel > 0) {
117 1         167 croak("Document ended with unmatched start tag(s): @elementStack");
118             } else {
119 78         106 @elementStack = ();
120 78         127 $elementLevel = 0;
121 78         131 %seen = ();
122 78         104 &{$end};
  78         141  
123             }
124 157         604 };
125              
126             my $xmlDecl = sub {
127 22     22   40 my ($encoding, $standalone) = (@_);
128 22 100 100     65 if ($standalone && $standalone ne 'no') {
129 1         3 $standalone = 'yes';
130             }
131              
132             # Only include an encoding if one has been explicitly supplied,
133             # either here or on construction. Allow the empty string
134             # to suppress it.
135 22 100       46 if (!defined($encoding)) {
136 18         25 $encoding = $outputEncoding;
137             }
138 22         72 $output->print("
139 21 100       173 if ($encoding) {
140 7         37 $output->print(" encoding=\"$encoding\"");
141             }
142 21 100       70 if ($standalone) {
143 2         9 $output->print(" standalone=\"$standalone\"");
144             }
145 21         65 $output->print("?>\n");
146 21         112 $hasHeading = 1;
147 157         674 };
148              
149             my $SAFE_xmlDecl = sub {
150 23 100   23   49 if ($seen{ANYTHING}) {
151 2         232 croak("The XML declaration is not the first thing in the document");
152             } else {
153 21         40 $seen{ANYTHING} = 1;
154 21         26 $seen{XMLDECL} = 1;
155 21         25 &{$xmlDecl};
  21         35  
156             }
157 157         487 };
158              
159             my $pi = sub {
160 8     8   11 my ($target, $data) = (@_);
161 8 100       13 if ($data) {
162 3         18 $output->print("");
163             } else {
164 5         19 $output->print("");
165             }
166 8 100       58 if ($elementLevel == 0) {
167 7         22 $output->print("\n");
168 7         43 $hasHeading = 1;
169             }
170 157         604 };
171              
172             my $SAFE_pi = sub {
173 11     11   19 my ($name, $data) = (@_);
174 11         22 $seen{ANYTHING} = 1;
175 11 100 100     69 if (($name =~ /^xml/i) && ($name !~ /^xml-(stylesheet|model)$/i)) {
176 1         215 carp("Processing instruction target begins with 'xml'");
177             }
178              
179 11 100 100     133 if ($name =~ /\?\>/ || (defined($data) && $data =~ /\?\>/)) {
    100 66        
180 2         400 croak("Processing instruction may not contain '?>'");
181             } elsif ($name =~ /\s/) {
182 1         193 croak("Processing instruction name may not contain whitespace");
183             } else {
184 8         9 &{$pi};
  8         16  
185             }
186 157         530 };
187              
188             my $comment = sub {
189 14     14   21 my $data = $_[0];
190 14 100 100     60 if ($dataMode && $elementLevel) {
191 5         13 $output->print("\n");
192 5         28 $output->print($dataIndent x $elementLevel);
193             }
194 14         72 $output->print("");
195 14 100 100     128 if ($dataMode && $elementLevel) {
    100          
196 5         12 $hasElement = 1;
197             } elsif ($elementLevel == 0) {
198 8         23 $output->print("\n");
199 8         49 $hasHeading = 1;
200             }
201 157         581 };
202              
203             my $SAFE_comment = sub {
204 14     14   22 my $data = $_[0];
205 14 100       74 if ($data =~ /--/) {
206 2         482 carp("Interoperability problem: \"--\" in comment text");
207             }
208              
209 14 100       175 if ($data =~ /-->/) {
210 1         103 croak("Comment may not contain '-->'");
211             } else {
212 13         17 &{$checkUnencodedRepertoire}($data);
  13         28  
213 12         21 $seen{ANYTHING} = 1;
214 12         17 &{$comment};
  12         22  
215             }
216 157         577 };
217              
218             my $doctype = sub {
219 10     10   21 my ($name, $publicId, $systemId) = (@_);
220 10         49 $output->print("
221 10 100       69 if ($publicId) {
    100          
222 5 100       11 unless ( defined $systemId) {
223 2         1046 croak("A DOCTYPE declaration with a public ID must also have a system ID");
224             }
225 3         14 $output->print(" PUBLIC \"$publicId\" \"$systemId\"");
226             } elsif ( defined $systemId ) {
227 2         8 $output->print(" SYSTEM \"$systemId\"");
228             }
229 8         47 $output->print(">\n");
230 8         41 $hasHeading = 1;
231 157         628 };
232              
233             my $SAFE_doctype = sub {
234 11     11   32 my $name = $_[0];
235 11 100       32 if ($seen{DOCTYPE}) {
    100          
236 1         142 croak("Attempt to insert second DOCTYPE declaration");
237             } elsif ($seen{ELEMENT}) {
238 1         138 croak("The DOCTYPE declaration must come before the first start tag");
239             } else {
240 9         29 $seen{ANYTHING} = 1;
241 9         11 $seen{DOCTYPE} = $name;
242 9         9 &{$doctype};
  9         18  
243             }
244 157         621 };
245              
246             my $startTag = sub {
247 105     105   152 my $name = $_[0];
248 105 100 100     372 if ($dataMode && ($hasHeading || $elementLevel)) {
      66        
249 29         94 $output->print("\n");
250 29         231 $output->print($dataIndent x $elementLevel);
251             }
252 105         225 $elementLevel++;
253 105         252 push @elementStack, $name;
254 105         445 $output->print("<$name");
255 104         586 &{$showAttributes}(\@_);
  104         234  
256 104         567 $output->print("$nl>");
257 104 100       703 if ($dataMode) {
258 43         65 $hasElement = 1;
259 43         169 push @hasDataStack, $hasData;
260 43         49 $hasData = 0;
261 43         60 push @hasElementStack, $hasElement;
262 43         158 $hasElement = 0;
263             }
264 157         631 };
265              
266             my $SAFE_startTag = sub {
267 103     103   150 my $name = $_[0];
268              
269 103         111 &{$checkUnencodedRepertoire}($name);
  103         217  
270 103         243 _checkAttributes(\@_);
271              
272 103 100 100     967 if ($seen{ELEMENT} && $elementLevel == 0) {
    100 100        
    100 100        
      100        
273 1         183 croak("Attempt to insert start tag after close of document element");
274             } elsif ($elementLevel == 0 && $seen{DOCTYPE} && $name ne $seen{DOCTYPE}) {
275 1         156 croak("Document element is \"$name\", but DOCTYPE is \""
276             . $seen{DOCTYPE}
277             . "\"");
278             } elsif ($dataMode && $hasData) {
279 2         563 croak("Mixed content not allowed in data mode: element $name");
280             } else {
281 99         223 $seen{ANYTHING} = 1;
282 99         753 $seen{ELEMENT} = 1;
283 99         107 &{$startTag};
  99         173  
284             }
285 157         558 };
286              
287             my $emptyTag = sub {
288 78     78   120 my $name = $_[0];
289 78 100 100     293 if ($dataMode && ($hasHeading || $elementLevel)) {
      66        
290 18         55 $output->print("\n");
291 18         171 $output->print($dataIndent x $elementLevel);
292             }
293 78         412 $output->print("<$name");
294 78         420 &{$showAttributes}(\@_);
  78         168  
295 78         490 $output->print("$nl />");
296 78 100       430 if ($dataMode) {
297 19         39 $hasElement = 1;
298             }
299 157         569 };
300              
301             my $SAFE_emptyTag = sub {
302 82     82   111 my $name = $_[0];
303              
304 82         84 &{$checkUnencodedRepertoire}($name);
  82         153  
305 81         306 _checkAttributes(\@_);
306              
307 78 100 100     675 if ($seen{ELEMENT} && $elementLevel == 0) {
    100 100        
    100 100        
      100        
308 1         267 croak("Attempt to insert empty tag after close of document element");
309             } elsif ($elementLevel == 0 && $seen{DOCTYPE} && $name ne $seen{DOCTYPE}) {
310 1         191 croak("Document element is \"$name\", but DOCTYPE is \""
311             . $seen{DOCTYPE}
312             . "\"");
313             } elsif ($dataMode && $hasData) {
314 1         172 croak("Mixed content not allowed in data mode: element $name");
315             } else {
316 75         194 $seen{ANYTHING} = 1;
317 75         105 $seen{ELEMENT} = 1;
318 75         82 &{$emptyTag};
  75         129  
319             }
320 157         649 };
321              
322             my $endTag = sub {
323 80     80   106 my $name = $_[0];
324 80         107 my $currentName = pop @elementStack;
325 80 100       172 $name = $currentName unless $name;
326 80         80 $elementLevel--;
327 80 100 100     245 if ($dataMode && $hasElement) {
328 20         61 $output->print("\n");
329 20         145 $output->print($dataIndent x $elementLevel);
330             }
331 80         457 $output->print("");
332 80 100       468 if ($dataMode) {
333 36         51 $hasData = pop @hasDataStack;
334 36         81 $hasElement = pop @hasElementStack;
335             }
336 157         568 };
337              
338             my $SAFE_endTag = sub {
339 76     76   99 my $name = $_[0];
340 76         273 my $oldName = $elementStack[$#elementStack];
341 76 100 100     376 if ($elementLevel <= 0) {
    100          
342 1         142 croak("End tag \"$name\" does not close any open element");
343             } elsif ($name && ($name ne $oldName)) {
344 1         254 croak("Attempt to end element \"$oldName\" with \"$name\" tag");
345             } else {
346 74         69 &{$endTag};
  74         167  
347             }
348 157         553 };
349              
350             my $characters = sub {
351 40     40   56 my $data = $_[0];
352 40 100       105 if ($data =~ /[\&\<\>]/) {
353 1         3 $data =~ s/\&/\&\;/g;
354 1         4 $data =~ s/\
355 1         3 $data =~ s/\>/\>\;/g;
356             }
357 40         43 &{$escapeEncoding}($data);
  40         72  
358 40         105 $output->print($data);
359 40         196 $hasData = 1;
360 157         496 };
361              
362             my $SAFE_characters = sub {
363 42 100 100 42   183 if ($elementLevel < 1) {
    100          
364 1         224 croak("Attempt to insert characters outside of document element");
365             } elsif ($dataMode && $hasElement) {
366 1         140 croak("Mixed content not allowed in data mode: characters");
367             } else {
368 40         79 _croakUnlessDefinedCharacters($_[0]);
369 38         38 &{$characters};
  38         68  
370             }
371 157         468 };
372              
373             my $raw = sub {
374 1     1   6 $output->print($_[0]);
375             # Don't set $hasData or any other information: we know nothing
376             # about what was just written.
377             #
378 157         439 };
379              
380             my $SAFE_raw = sub {
381 1     1   178 croak('raw() is only available when UNSAFE is set');
382 157         423 };
383              
384             my $cdata = sub {
385 10     10   16 my $data = $_[0];
386 10         25 $data =~ s/\]\]>/\]\]\]\]>/g;
387 10         45 $output->print("");
388 10         59 $hasData = 1;
389 157         505 };
390              
391             my $SAFE_cdata = sub {
392 11 100 100 11   51 if ($elementLevel < 1) {
    100          
393 1         149 croak("Attempt to insert characters outside of document element");
394             } elsif ($dataMode && $hasElement) {
395 1         139 croak("Mixed content not allowed in data mode: characters");
396             } else {
397 9         80 _croakUnlessDefinedCharacters($_[0]);
398 8         10 &{$checkUnencodedRepertoire}($_[0]);
  8         19  
399 7         11 &{$cdata};
  7         13  
400             }
401 157         1118 };
402              
403             # Assign the correct closures based on
404             # the UNSAFE parameter
405 157 100       356 if ($unsafe) {
406 9         80 $self = {'END' => $end,
407             'XMLDECL' => $xmlDecl,
408             'PI' => $pi,
409             'COMMENT' => $comment,
410             'DOCTYPE' => $doctype,
411             'STARTTAG' => $startTag,
412             'EMPTYTAG' => $emptyTag,
413             'ENDTAG' => $endTag,
414             'CHARACTERS' => $characters,
415             'RAW' => $raw,
416             'CDATA' => $cdata
417             };
418             } else {
419 148         1225 $self = {'END' => $SAFE_end,
420             'XMLDECL' => $SAFE_xmlDecl,
421             'PI' => $SAFE_pi,
422             'COMMENT' => $SAFE_comment,
423             'DOCTYPE' => $SAFE_doctype,
424             'STARTTAG' => $SAFE_startTag,
425             'EMPTYTAG' => $SAFE_emptyTag,
426             'ENDTAG' => $SAFE_endTag,
427             'CHARACTERS' => $SAFE_characters,
428             'RAW' => $SAFE_raw, # This will intentionally fail
429             'CDATA' => $SAFE_cdata
430             };
431             }
432              
433             # Query methods
434             $self->{'IN_ELEMENT'} = sub {
435 1     1   2 my ($ancestor) = (@_);
436 1         6 return $elementStack[$#elementStack] eq $ancestor;
437 157         1107 };
438              
439             $self->{'WITHIN_ELEMENT'} = sub {
440 3     3   6 my ($ancestor) = (@_);
441 3         4 my $el;
442 3         6 foreach $el (@elementStack) {
443 4 100       17 return 1 if $el eq $ancestor;
444             }
445 1         8 return 0;
446 157         618 };
447              
448             $self->{'CURRENT_ELEMENT'} = sub {
449 1     1   26 return $elementStack[$#elementStack];
450 157         603 };
451              
452             $self->{'ANCESTOR'} = sub {
453 5     5   6 my ($n) = (@_);
454 5 100       14 if ($n < scalar(@elementStack)) {
455 3         16 return $elementStack[$#elementStack-$n];
456             } else {
457 2         10 return undef;
458             }
459 157         568 };
460              
461             # Set and get the output destination.
462             $self->{'GETOUTPUT'} = sub {
463 7 100   7   17 if (ref($output) ne 'XML::Writer::_PrintChecker') {
464 4         16 return $output;
465             } else {
466 3         15 return $output->{HANDLE};
467             }
468 157         832 };
469              
470             $self->{'SETOUTPUT'} = sub {
471 163     163   198 my $newOutput = $_[0];
472              
473 163 100 100     869 if (defined($newOutput) && !ref($newOutput) && 'self' eq $newOutput ) {
      66        
474 2         3 $newOutput = \$selfcontained_output;
475 2         4 $use_selfcontained_output = 1;
476             }
477              
478 163 100       319 if (ref($newOutput) eq 'SCALAR') {
479 7         28 $output = XML::Writer::_String->new($newOutput);
480             } else {
481             # If there is no OUTPUT parameter,
482             # use standard output
483 156   100     429 $output = $newOutput || \*STDOUT;
484 156 100 100     440 if ($outputEncoding && (ref($output) eq 'GLOB' || $output->isa('IO::Handle'))) {
      66        
485 14 100       52 if (lc($outputEncoding) eq 'utf-8') {
    100          
486 1     1   11 binmode($output, ':encoding(utf-8)');
  1         4  
  1         8  
  2         53  
487             } elsif (lc($outputEncoding) eq 'us-ascii') {
488 10         114 binmode($output, ':encoding(us-ascii)');
489             } else {
490 2         175 die 'The only supported encodings are utf-8 and us-ascii';
491             }
492             }
493             }
494              
495 161 100       16005 if ($params{CHECK_PRINT}) {
496 6         16 $output = XML::Writer::_PrintChecker->new($output);
497             }
498 157         639 };
499              
500             $self->{OVERLOADSTRING} = sub {
501             # if we don't use the self-contained output,
502             # simple passthrough
503 5 100   5   54 return $use_selfcontained_output ? $selfcontained_output : undef;
504 157         593 };
505              
506             $self->{TOSTRING} = sub {
507 2 100   2   14 die "'to_string' can only be used with self-contained output\n"
508             unless $use_selfcontained_output;
509              
510 1         5 return $selfcontained_output;
511 157         653 };
512              
513             $self->{'SETDATAMODE'} = sub {
514 7     7   25 $dataMode = $_[0];
515 157         507 };
516              
517             $self->{'GETDATAMODE'} = sub {
518 2     2   10 return $dataMode;
519 157         529 };
520              
521             $self->{'SETDATAINDENT'} = sub {
522 165 100   165   683 if ($_[0] =~ /^\s*$/) {
523 155         270 $dataIndent = $_[0];
524             } else {
525 10         52 $dataIndent = ' ' x $_[0];
526             }
527 157         487 };
528              
529             $self->{'GETDATAINDENT'} = sub {
530 8 100   8   34 if ($dataIndent =~ /^ *$/) {
531 7         39 return length($dataIndent);
532             } else {
533 1         5 return $dataIndent;
534             }
535 157         452 };
536              
537             # Set the indent.
538 157   100     618 &{$self->{'SETDATAINDENT'}}($params{'DATA_INDENT'} || '');
  157         424  
539              
540             # Set the output.
541 157         251 &{$self->{'SETOUTPUT'}}($params{'OUTPUT'});
  157         817  
542              
543             # Return the blessed object.
544 155         1516 return bless $self, $class;
545             }
546              
547              
548            
549             ########################################################################
550             # Public methods
551             ########################################################################
552              
553             #
554             # Finish writing the document.
555             #
556             sub end {
557 89     89 1 1536 my $self = shift;
558 89         102 &{$self->{END}};
  89         202  
559             }
560              
561             #
562             # Write an XML declaration.
563             #
564             sub xmlDecl {
565 24     24 1 6591 my $self = shift;
566 24         38 &{$self->{XMLDECL}};
  24         70  
567             }
568              
569             #
570             # Write a processing instruction.
571             #
572             sub pi {
573 12     12 1 1533 my $self = shift;
574 12         19 &{$self->{PI}};
  12         34  
575             }
576              
577             #
578             # Write a comment.
579             #
580             sub comment {
581 16     16 1 3260 my $self = shift;
582 16         32 &{$self->{COMMENT}};
  16         42  
583             }
584              
585             #
586             # Write a DOCTYPE declaration.
587             #
588             sub doctype {
589 12     12 1 1618 my $self = shift;
590 12         16 &{$self->{DOCTYPE}};
  12         27  
591             }
592              
593             #
594             # Write a start tag.
595             #
596             sub startTag {
597 109     109 1 6582 my $self = shift;
598 109         133 &{$self->{STARTTAG}};
  109         737  
599             }
600              
601             #
602             # Write an empty tag.
603             #
604             sub emptyTag {
605 90     90 1 4176 my $self = shift;
606 90         129 &{$self->{EMPTYTAG}};
  90         266  
607             }
608              
609             #
610             # Write an end tag.
611             #
612             sub endTag {
613 82     82 1 438 my $self = shift;
614 82         100 &{$self->{ENDTAG}};
  82         188  
615             }
616              
617             #
618             # Write a simple data element.
619             #
620             sub dataElement {
621 20     20 1 1113 my ($self, $name, $data, @atts) = (@_);
622 20         55 $self->startTag($name, @atts);
623 20         62 $self->characters($data);
624 20         55 $self->endTag($name);
625             }
626              
627             #
628             # Write a simple CDATA element.
629             #
630             sub cdataElement {
631 1     1 1 158 my ($self, $name, $data, %atts) = (@_);
632 1         4 $self->startTag($name, %atts);
633 1         6 $self->cdata($data);
634 1         4 $self->endTag($name);
635             }
636              
637             #
638             # Write character data.
639             #
640             sub characters {
641 44     44 1 489 my $self = shift;
642 44         55 &{$self->{CHARACTERS}};
  44         200  
643             }
644              
645             #
646             # Write raw, unquoted, completely unchecked character data.
647             #
648             sub raw {
649 2     2 1 18 my $self = shift;
650 2         3 &{$self->{RAW}};
  2         8  
651             }
652              
653             #
654             # Write CDATA.
655             #
656             sub cdata {
657 14     14 1 187 my $self = shift;
658 14         21 &{$self->{CDATA}};
  14         35  
659             }
660              
661             #
662             # Query the current element.
663             #
664             sub in_element {
665 1     1 1 11 my $self = shift;
666 1         3 return &{$self->{IN_ELEMENT}};
  1         5  
667             }
668              
669             #
670             # Query the ancestors.
671             #
672             sub within_element {
673 3     3 1 20 my $self = shift;
674 3         3 return &{$self->{WITHIN_ELEMENT}};
  3         8  
675             }
676              
677             #
678             # Get the name of the current element.
679             #
680             sub current_element {
681 1     1 1 9 my $self = shift;
682 1         4 return &{$self->{CURRENT_ELEMENT}};
  1         4  
683             }
684              
685             #
686             # Get the name of the numbered ancestor (zero-based).
687             #
688             sub ancestor {
689 5     5 1 134 my $self = shift;
690 5         6 return &{$self->{ANCESTOR}};
  5         13  
691             }
692              
693             #
694             # Get the current output destination.
695             #
696             sub getOutput {
697 7     7 1 602 my $self = shift;
698 7         10 return &{$self->{GETOUTPUT}};
  7         19  
699             }
700              
701              
702             #
703             # Set the current output destination.
704             #
705             sub setOutput {
706 6     6 1 644 my $self = shift;
707 6         6 return &{$self->{SETOUTPUT}};
  6         15  
708             }
709              
710             #
711             # Set the current data mode (true or false).
712             #
713             sub setDataMode {
714 7     7 1 789 my $self = shift;
715 7         12 return &{$self->{SETDATAMODE}};
  7         18  
716             }
717              
718              
719             #
720             # Get the current data mode (true or false).
721             #
722             sub getDataMode {
723 2     2 1 208 my $self = shift;
724 2         3 return &{$self->{GETDATAMODE}};
  2         7  
725             }
726              
727              
728             #
729             # Set the current data indent step.
730             #
731             sub setDataIndent {
732 8     8 1 162 my $self = shift;
733 8         9 return &{$self->{SETDATAINDENT}};
  8         42  
734             }
735              
736              
737             #
738             # Get the current data indent step.
739             #
740             sub getDataIndent {
741 8     8 1 296 my $self = shift;
742 8         10 return &{$self->{GETDATAINDENT}};
  8         21  
743             }
744              
745              
746             #
747             # Empty stub.
748             #
749 1     1 1 151 sub addPrefix {
750             }
751              
752              
753             #
754             # Empty stub.
755             #
756 1     1 1 5 sub removePrefix {
757             }
758              
759             sub to_string {
760 2     2 1 4 my $self = shift;
761              
762 2         42 $self->{TOSTRING}->();
763             }
764              
765              
766            
767             ########################################################################
768             # Private functions.
769             ########################################################################
770              
771             #
772             # Private: check for duplicate attributes and bad characters.
773             # Note - this starts at $_[1], because $_[0] is assumed to be an
774             # element name.
775             #
776             sub _checkAttributes {
777 184     184   191 my %anames;
778 184         220 my $i = 1;
779 184         550 while ($_[0]->[$i]) {
780 69         114 my $name = $_[0]->[$i];
781 69         115 $i += 1;
782 69 100       148 if ($anames{$name}) {
783 2         578 croak("Two attributes named \"$name\"");
784             } else {
785 67         145 $anames{$name} = 1;
786             }
787 67         153 _croakUnlessDefinedCharacters($_[0]->[$i]);
788 66         229 $i += 1;
789             }
790             }
791              
792             #
793             # Private: escape an attribute value literal.
794             #
795             sub _escapeLiteral {
796 71     71   114 my $data = $_[0];
797 71 100       198 if ($data =~ /[\&\<\>\"]/) {
798 2         5 $data =~ s/\&/\&\;/g;
799 2         4 $data =~ s/\
800 2         8 $data =~ s/\>/\>\;/g;
801 2         3 $data =~ s/\"/\"\;/g;
802             }
803 71         126 return $data;
804             }
805              
806             sub _escapeASCII($) {
807 7     7   24 $_[0] =~ s/([^\x00-\x7F])/sprintf('&#x%X;', ord($1))/ge;
  5         23  
808             }
809              
810             sub _croakUnlessASCII($) {
811 15 100   15   48 if ($_[0] =~ /[^\x00-\x7F]/) {
812 3         511 croak('Non-ASCII characters are not permitted in this part of a US-ASCII document');
813             }
814             }
815              
816             # Enforce XML 1.0, section 2.2's definition of "Char" (only reject low ASCII,
817             # so as not to require Unicode support from perl)
818             sub _croakUnlessDefinedCharacters($) {
819 116 100   116   592 if ($_[0] =~ /([\x00-\x08\x0B-\x0C\x0E-\x1F])/) {
820 4         724 croak(sprintf('Code point \u%04X is not a valid character in XML', ord($1)));
821             }
822             }
823              
824             sub _overload_string {
825 5     5   1083 my $self = shift;
826 5 100       13 $self->{OVERLOADSTRING}->() || overload::StrVal($self);
827             }
828            
829             ########################################################################
830             # XML::Writer::Namespaces - subclass for Namespace processing.
831             ########################################################################
832              
833             package XML::Writer::Namespaces;
834 2     2   13895 use strict;
  2         5  
  2         96  
835 2     2   10 use vars qw(@ISA);
  2         3  
  2         109  
836 2     2   11 use Carp;
  2         4  
  2         5832  
837              
838             @ISA = qw(XML::Writer);
839              
840             #
841             # Constructor
842             #
843             sub new {
844 146     146   333 my ($class, %params) = (@_);
845              
846 146         246 my $unsafe = $params{UNSAFE};
847              
848             # Snarf the prefix map, if any, and
849             # note the default prefix.
850 146         236 my %prefixMap = ();
851 146 100       336 if ($params{PREFIX_MAP}) {
852 8         9 %prefixMap = (%{$params{PREFIX_MAP}});
  8         28  
853 8         18 delete $params{PREFIX_MAP};
854             }
855 146         277 $prefixMap{'http://www.w3.org/XML/1998/namespace'} = 'xml';
856              
857             # Generate the reverse map for URIs
858 146         230 my $uriMap = {};
859 146         180 my $key;
860 146         444 foreach $key (keys(%prefixMap)) {
861 155         499 $uriMap->{$prefixMap{$key}} = $key;
862             }
863              
864 146         347 my $defaultPrefix = $uriMap->{''};
865 146 100       259 delete $prefixMap{$defaultPrefix} if ($defaultPrefix);
866              
867             # Create an instance of the parent.
868 146         421 my $self = XML::Writer->new(%params);
869              
870             # Snarf the parent's methods that we're
871             # going to override.
872 144         688 my $OLD_startTag = $self->{STARTTAG};
873 144         203 my $OLD_emptyTag = $self->{EMPTYTAG};
874 144         197 my $OLD_endTag = $self->{ENDTAG};
875              
876             # State variables
877 144         181 my @stack;
878 144         166 my $prefixCounter = 1;
879 144         374 my $nsDecls = {'http://www.w3.org/XML/1998/namespace' => 'xml'};
880 144         193 my $nsDefaultDecl = undef;
881 144         163 my $nsCopyFlag = 0;
882 144         286 my @forcedNSDecls = ();
883              
884 144 100       295 if ($params{FORCED_NS_DECLS}) {
885 2         4 @forcedNSDecls = @{$params{FORCED_NS_DECLS}};
  2         6  
886 2         5 delete $params{FORCED_NS_DECLS};
887             }
888              
889             #
890             # Push the current declaration state.
891             #
892             my $pushState = sub {
893 181     181   473 push @stack, [$nsDecls, $nsDefaultDecl, $nsCopyFlag, $uriMap];
894 181         269 $nsCopyFlag = 0;
895 144         520 };
896              
897              
898             #
899             # Pop the current declaration state.
900             #
901             my $popState = sub {
902 146     146   715 ($nsDecls, $nsDefaultDecl, $nsCopyFlag, $uriMap) = @{pop @stack};
  146         637  
903 144         473 };
904              
905             #
906             # Generate a new prefix.
907             #
908             my $genPrefix = sub {
909 34     34   55 my $uri = $_[0];
910 34         38 my $prefixCounter = 1;
911 34         54 my $prefix = $prefixMap{$uri};
912 34         39 my %clashMap = %{$uriMap};
  34         146  
913 34         138 while( my ($u, $p) = each(%prefixMap)) {
914 45         168 $clashMap{$p} = $u;
915             }
916              
917 34   100     231 while (!defined($prefix) || ($clashMap{$prefix} && $clashMap{$prefix} ne $uri)) {
      66        
918 36         73 $prefix = "__NS$prefixCounter";
919 36         271 $prefixCounter++;
920             }
921              
922 34         117 return $prefix;
923 144         713 };
924              
925             #
926             # Perform namespace processing on a single name.
927             #
928             my $processName = sub {
929 71     71   105 my ($nameref, $atts, $attFlag) = (@_);
930 71         72 my ($uri, $local) = @{$$nameref};
  71         136  
931 71         119 my $prefix = $nsDecls->{$uri};
932              
933             # Is this an element name that matches
934             # the default NS?
935 71 100 100     407 if (!$attFlag && $defaultPrefix && ($uri eq $defaultPrefix)) {
    100 100        
936 17 100 100     57 unless ($nsDefaultDecl && ($nsDefaultDecl eq $uri)) {
937 12         14 push @{$atts}, 'xmlns';
  12         19  
938 12         12 push @{$atts}, $uri;
  12         18  
939 12         18 $nsDefaultDecl = $uri;
940             }
941 17         24 $$nameref = $local;
942              
943 17 100       40 if (defined($uriMap->{''})) {
944 9         21 delete ($nsDecls->{$uriMap->{''}});
945             }
946              
947 17         30 $nsDecls->{$uri} = '';
948 17 100       36 unless ($nsCopyFlag) {
949 16         18 $uriMap = {%{$uriMap}};
  16         57  
950 16         25 $nsDecls = {%{$nsDecls}};
  16         49  
951 16         26 $nsCopyFlag = 1;
952             }
953 17         43 $uriMap->{''} = $uri;
954              
955             # Is there a straight-forward prefix?
956             } elsif ($prefix) {
957 20         63 $$nameref = "$prefix:$local";
958             } else {
959 34         40 $prefix = &{$genPrefix}($uri);
  34         76  
960 34 100       87 unless ($nsCopyFlag) {
961 30         53 $uriMap = {%{$uriMap}};
  30         117  
962 30         45 $nsDecls = {%{$nsDecls}};
  30         310  
963 30         49 $nsCopyFlag = 1;
964             }
965 34         184 $uriMap->{$prefix} = $uri;
966 34         77 $nsDecls->{$uri} = $prefix;
967 34         44 push @{$atts}, "xmlns:$prefix";
  34         262  
968 34         207 push @{$atts}, $uri;
  34         67  
969 34         102 $$nameref = "$prefix:$local";
970             }
971 144         663 };
972              
973              
974             #
975             # Perform namespace processing on element and attribute names.
976             #
977             my $nsProcess = sub {
978 181 100   181   482 if (ref($_[0]->[0]) eq 'ARRAY') {
979 54         56 my $x = \@{$_[0]->[0]};
  54         99  
980 54         84 &{$processName}(\$x, $_[0], 0);
  54         112  
981 54         75 splice(@{$_[0]}, 0, 1, $x);
  54         146  
982             }
983 181         344 my $i = 1;
984 181         427 while ($_[0]->[$i]) {
985 70 100       184 if (ref($_[0]->[$i]) eq 'ARRAY') {
986 14         21 my $x = \@{$_[0]->[$i]};
  14         31  
987 14         29 &{$processName}(\$x, $_[0], 1);
  14         36  
988 14         483 splice(@{$_[0]}, $i, 1, $x);
  14         49  
989             }
990 70         186 $i += 2;
991             }
992              
993             # We do this if any declarations are forced, due either to
994             # constructor arguments or to a call during processing.
995 181 100       7045 if (@forcedNSDecls) {
996 3         6 foreach (@forcedNSDecls) {
997 3         6 my @dummy = ($_, 'dummy');
998 3         4 my $d2 = \@dummy;
999 3 100 100     15 if ($defaultPrefix && ($_ eq $defaultPrefix)) {
1000 1         3 &{$processName}(\$d2, $_[0], 0);
  1         4  
1001             } else {
1002 2         4 &{$processName}(\$d2, $_[0], 1);
  2         5  
1003             }
1004             }
1005 3         7 @forcedNSDecls = ();
1006             }
1007 144         655 };
1008              
1009              
1010             # Indicate that a namespace should be declared by the next open element
1011             $self->{FORCENSDECL} = sub {
1012 1     1   3 push @forcedNSDecls, $_[0];
1013 144         518 };
1014              
1015              
1016             #
1017             # Start tag, with NS processing
1018             #
1019             $self->{STARTTAG} = sub {
1020 100     100   282 my $name = $_[0];
1021 100 100       228 unless ($unsafe) {
1022 94         216 _checkNSNames(\@_);
1023             }
1024 100         134 &{$pushState}();
  100         188  
1025 100         152 &{$nsProcess}(\@_);
  100         209  
1026 100         137 &{$OLD_startTag};
  100         180  
1027 144         577 };
1028              
1029              
1030             #
1031             # Empty tag, with NS processing
1032             #
1033             $self->{EMPTYTAG} = sub {
1034 86 100   86   178 unless ($unsafe) {
1035 83         176 _checkNSNames(\@_);
1036             }
1037 81         124 &{$pushState}();
  81         147  
1038 81         114 &{$nsProcess}(\@_);
  81         148  
1039 81         98 &{$OLD_emptyTag};
  81         197  
1040 75         88 &{$popState}();
  75         144  
1041 144         620 };
1042              
1043              
1044             #
1045             # End tag, with NS processing
1046             #
1047             $self->{ENDTAG} = sub {
1048 73     73   283 my $name = $_[0];
1049 73 100       156 if (ref($_[0]) eq 'ARRAY') {
1050 22         56 my $pfx = $nsDecls->{$_[0]->[0]};
1051 22 100       47 if ($pfx) {
1052 17         57 $_[0] = $pfx . ':' . $_[0]->[1];
1053             } else {
1054 5         10 $_[0] = $_[0]->[1];
1055             }
1056             } else {
1057 51         61 $_[0] = $_[0];
1058             }
1059             # &{$nsProcess}(\@_);
1060 73         86 &{$OLD_endTag};
  73         127  
1061 71         98 &{$popState}();
  71         174  
1062 144         998 };
1063              
1064              
1065             #
1066             # Processing instruction, but only if not UNSAFE.
1067             #
1068 144 100       323 unless ($unsafe) {
1069 135         201 my $OLD_pi = $self->{PI};
1070             $self->{PI} = sub {
1071 12     12   42 my $target = $_[0];
1072 12 100       38 if (index($target, ':') >= 0) {
1073 1         168 croak "PI target '$target' contains a colon.";
1074             }
1075 11         13 &{$OLD_pi};
  11         20  
1076             }
1077 135         526 };
1078              
1079              
1080             #
1081             # Add a prefix to the prefix map.
1082             #
1083             $self->{ADDPREFIX} = sub {
1084 18     18   40 my ($uri, $prefix) = (@_);
1085 18 100       32 if ($prefix) {
1086 7         24 $prefixMap{$uri} = $prefix;
1087             } else {
1088 11 100       27 if (defined($defaultPrefix)) {
1089 4         8 delete($prefixMap{$defaultPrefix});
1090             }
1091 11         29 $defaultPrefix = $uri;
1092             }
1093 144         761 };
1094              
1095              
1096             #
1097             # Remove a prefix from the prefix map.
1098             #
1099             $self->{REMOVEPREFIX} = sub {
1100 3     3   5 my ($uri) = (@_);
1101 3 100 100     14 if ($defaultPrefix && ($defaultPrefix eq $uri)) {
1102 1         2 $defaultPrefix = undef;
1103             }
1104 3         9 delete $prefixMap{$uri};
1105 144         822 };
1106              
1107              
1108             #
1109             # Bless and return the object.
1110             #
1111 144         4025 return bless $self, $class;
1112             }
1113              
1114              
1115             #
1116             # Add a preferred prefix for a namespace URI.
1117             #
1118             sub addPrefix {
1119 18     18   1899 my $self = shift;
1120 18         26 return &{$self->{ADDPREFIX}};
  18         42  
1121             }
1122              
1123              
1124             #
1125             # Remove a preferred prefix for a namespace URI.
1126             #
1127             sub removePrefix {
1128 3     3   351 my $self = shift;
1129 3         4 return &{$self->{REMOVEPREFIX}};
  3         7  
1130             }
1131              
1132              
1133             #
1134             # Check names.
1135             #
1136             sub _checkNSNames {
1137 177     177   379 my $names = $_[0];
1138 177         201 my $i = 1;
1139 177         360 my $name = $names->[0];
1140              
1141             # Check the element name.
1142 177 100       798 if (ref($name) eq 'ARRAY') {
    100          
1143 55 100       178 if (index($name->[1], ':') >= 0) {
1144 1         172 croak("Local part of element name '" .
1145             $name->[1] .
1146             "' contains a colon.");
1147             }
1148             } elsif (index($name, ':') >= 0) {
1149 1         181 croak("Element name '$name' contains a colon.");
1150             }
1151              
1152             # Check the attribute names.
1153 175         556 while ($names->[$i]) {
1154 25         47 my $name = $names->[$i];
1155 25 100       261 if (ref($name) eq 'ARRAY') {
1156 13         1450 my $local = $name->[1];
1157 13 100       67 if (index($local, ':') >= 0) {
1158 1         181 croak "Local part of attribute name '$local' contains a colon.";
1159             }
1160             } else {
1161 12 100       51 if ($name =~ /^xmlns/) {
    100          
1162 1         246 croak "Attribute name '$name' begins with 'xmlns'";
1163             } elsif (index($name, ':') >= 0) {
1164 1         178 croak "Attribute name '$name' contains ':'";
1165             }
1166             }
1167 22         92 $i += 2;
1168             }
1169             }
1170              
1171             sub forceNSDecl
1172             {
1173 1     1   5 my $self = shift;
1174 1         2 return &{$self->{FORCENSDECL}};
  1         4  
1175             }
1176              
1177              
1178             package XML::Writer::_String;
1179              
1180             # Internal class, behaving sufficiently like an IO::Handle,
1181             # that stores written output in a string
1182             #
1183             # Heavily inspired by Simon Oliver's XML::Writer::String
1184              
1185             sub new
1186             {
1187 7     7   9 my $class = shift;
1188 7         14 my $scalar_ref = shift;
1189 7         25 return bless($scalar_ref, $class);
1190             }
1191              
1192             sub print
1193             {
1194 43     43   45 ${(shift)} .= join('', @_);
  43         88  
1195 43         63 return 1;
1196             }
1197              
1198              
1199             package XML::Writer::_PrintChecker;
1200              
1201 2     2   22 use Carp;
  2         99  
  2         380  
1202              
1203             sub new
1204             {
1205 6     6   11 my $class = shift;
1206 6         29 return bless({HANDLE => shift}, $class);
1207             }
1208              
1209             sub print
1210             {
1211 4     4   5 my $self = shift;
1212 4 100       17 if ($self->{HANDLE}->print(shift)) {
1213 2         12 return 1;
1214             } else {
1215 2         240 croak "Failed to write output: $!";
1216             }
1217             }
1218              
1219             1;
1220             __END__