File Coverage

blib/lib/XML/SAX/Writer.pm
Criterion Covered Total %
statement 134 141 95.0
branch 30 36 83.3
condition 18 27 66.6
subroutine 35 38 92.1
pod 8 9 88.8
total 225 251 89.6


line stmt bran cond sub pod time code
1             package XML::SAX::Writer;
2             $XML::SAX::Writer::VERSION = '0.56';
3 3     3   45414 use strict;
  3         4  
  3         110  
4 3     3   12 use vars qw(%DEFAULT_ESCAPE %COMMENT_ESCAPE);
  3         2  
  3         168  
5              
6             # ABSTRACT: SAX2 XML Writer
7              
8 3     3   1609 use Encode qw();
  3         23522  
  3         69  
9 3     3   1317 use XML::SAX::Exception qw();
  3         6848  
  3         53  
10 3     3   1169 use XML::SAX::Writer::XML qw();
  3         7  
  3         69  
11 3     3   1367 use XML::Filter::BufferText qw();
  3         47215  
  3         4426  
12             @XML::SAX::Writer::Exception::ISA = qw(XML::SAX::Exception);
13              
14              
15             %DEFAULT_ESCAPE = (
16             '&' => '&',
17             '<' => '<',
18             '>' => '>',
19             '"' => '"',
20             "'" => ''',
21             );
22              
23             %COMMENT_ESCAPE = (
24             '--' => '--',
25             );
26              
27              
28             #-------------------------------------------------------------------#
29             # new
30             #-------------------------------------------------------------------#
31             sub new {
32 7 50   7 1 4260 my $class = ref($_[0]) ? ref(shift) : shift;
33 7 100       19 my $opt = (@_ == 1) ? { %{shift()} } : {@_};
  4         15  
34              
35             # default the options
36 7   50     34 $opt->{Writer} ||= 'XML::SAX::Writer::XML';
37 7   100     26 $opt->{Escape} ||= \%DEFAULT_ESCAPE;
38 7   50     29 $opt->{CommentEscape} ||= \%COMMENT_ESCAPE;
39 7 100       19 $opt->{EncodeFrom} = exists $opt->{EncodeFrom} ? $opt->{EncodeFrom} : 'utf-8';
40 7 100       13 $opt->{EncodeTo} = exists $opt->{EncodeTo} ? $opt->{EncodeTo} : 'utf-8';
41 7   100     27 $opt->{Format} ||= {}; # needs options w/ defaults, we'll see later
42 7   100     25 $opt->{Output} ||= *{STDOUT}{IO};
43 7   100     27 $opt->{QuoteCharacter} ||= q['];
44              
45 3     3   15 eval "use $opt->{Writer};";
  3     3   22  
  3     1   67  
  3         15  
  3         3  
  3         40  
  1         5  
  1         1  
  1         12  
  7         704  
46              
47 7         20 my $obj = bless $opt, $opt->{Writer};
48 7         28 $obj->init;
49              
50             # we need to buffer the text to escape it right
51 7         42 my $bf = XML::Filter::BufferText->new( Handler => $obj );
52              
53 7         320 return $bf;
54             }
55             #-------------------------------------------------------------------#
56              
57             #-------------------------------------------------------------------#
58             # init
59             #-------------------------------------------------------------------#
60 7     7 1 7 sub init {} # noop, for subclasses
61             #-------------------------------------------------------------------#
62              
63             #-------------------------------------------------------------------#
64             # setConverter
65             #-------------------------------------------------------------------#
66             sub setConverter {
67 13     13 1 15 my $self = shift;
68              
69 13 100       39 if (lc($self->{EncodeFrom}) ne lc($self->{EncodeTo})) {
70 10         34 $self->{Encoder} = XML::SAX::Writer::Encode->new($self->{EncodeFrom}, $self->{EncodeTo});
71             }
72             else {
73 3         17 $self->{Encoder} = XML::SAX::Writer::NullConverter->new;
74             }
75 13         31 return $self;
76             }
77             #-------------------------------------------------------------------#
78              
79             #-------------------------------------------------------------------#
80             # setConsumer
81             #-------------------------------------------------------------------#
82             sub setConsumer {
83 13     13 1 15 my $self = shift;
84              
85             # create the Consumer
86 13         23 my $ref = ref $self->{Output};
87 13 100 66     114 if ($ref eq 'SCALAR') {
    100 100        
    100          
    100          
    100          
    100          
88 3         14 $self->{Consumer} = XML::SAX::Writer::StringConsumer->new($self->{Output});
89             }
90             elsif ($ref eq 'CODE') {
91 1         5 $self->{Consumer} = XML::SAX::Writer::CodeConsumer->new($self->{Output});
92             }
93             elsif ($ref eq 'ARRAY') {
94 1         5 $self->{Consumer} = XML::SAX::Writer::ArrayConsumer->new($self->{Output});
95             }
96             elsif (
97             $ref eq 'GLOB' or
98             UNIVERSAL::isa(\$self->{Output}, 'GLOB') or
99             UNIVERSAL::isa($self->{Output}, 'IO::Handle')) {
100 4         17 $self->{Consumer} = XML::SAX::Writer::HandleConsumer->new($self->{Output});
101             }
102             elsif (not $ref) {
103 1         6 $self->{Consumer} = XML::SAX::Writer::FileConsumer->new($self->{Output});
104             }
105             elsif (UNIVERSAL::can($self->{Output}, 'output')) {
106 2         6 $self->{Consumer} = $self->{Output};
107             }
108             else {
109 1         16 XML::SAX::Writer::Exception->throw( Message => 'Unknown option for Output' );
110             }
111 12         63 return $self;
112             }
113             #-------------------------------------------------------------------#
114              
115             #-------------------------------------------------------------------#
116             # setEscaperRegex
117             #-------------------------------------------------------------------#
118             sub setEscaperRegex {
119 13     13 1 10 my $self = shift;
120              
121 65         989 $self->{EscaperRegex} = eval 'qr/' .
122 13         16 join( '|', map { $_ = "\Q$_\E" } keys %{$self->{Escape}}) .
  13         35  
123             '/;' ;
124 13         54 return $self;
125             }
126             #-------------------------------------------------------------------#
127              
128             #-------------------------------------------------------------------#
129             # setCommentEscaperRegex
130             #-------------------------------------------------------------------#
131             sub setCommentEscaperRegex {
132 13     13 1 13 my $self = shift;
133              
134 13         656 $self->{CommentEscaperRegex} =
135             eval 'qr/' .
136 13         16 join( '|', map { $_ = "\Q$_\E" } keys %{$self->{CommentEscape}}) .
  13         29  
137             '/;' ;
138 13         40 return $self;
139             }
140             #-------------------------------------------------------------------#
141              
142             #-------------------------------------------------------------------#
143             # escape
144             #-------------------------------------------------------------------#
145             sub escape {
146 3     3 1 742 my $self = shift;
147 3         4 my $str = shift;
148              
149 3         64 $str =~ s/($self->{EscaperRegex})/$self->{Escape}->{$1}/ge;
  5         14  
150 3         10 return $str;
151             }
152             #-------------------------------------------------------------------#
153              
154             #-------------------------------------------------------------------#
155             # escapeComment
156             #-------------------------------------------------------------------#
157             sub escapeComment {
158 0     0 1 0 my $self = shift;
159 0         0 my $str = shift;
160              
161 0         0 $str =~ s/($self->{CommentEscaperRegex})/$self->{CommentEscape}->{$1}/ge;
  0         0  
162 0         0 return $str;
163             }
164             #-------------------------------------------------------------------#
165              
166             #-------------------------------------------------------------------#
167             # convert and checking the return value
168             #-------------------------------------------------------------------#
169             sub safeConvert {
170 8     8 0 8 my $self = shift;
171 8         9 my $str = shift;
172              
173 8         15 my $out = $self->{Encoder}->convert($str);
174              
175 8 100 66     21 if (!defined $out && defined $str) {
176 1         6 warn "Conversion error returned by Encoder [$self->{Encoder}], string: '$str'";
177 1         2 $out = '_LOST_DATA_';
178             }
179 8         16 return $out;
180             }
181             #-------------------------------------------------------------------#
182              
183              
184             #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
185             #`,`, The Empty Consumer ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
186             #```````````````````````````````````````````````````````````````````#
187              
188             # this package is only there to provide a smooth upgrade path in case
189             # new methods are added to the interface
190              
191             package XML::SAX::Writer::ConsumerInterface;
192             $XML::SAX::Writer::ConsumerInterface::VERSION = '0.56';
193             sub new {
194 15     15   1621 my $class = shift;
195 15         16 my $ref = shift;
196             ## $self is a reference to the reference that we will send output
197             ## to. This allows us to bless $self without blessing $$self.
198 15   33     84 return bless \$ref, ref $class || $class;
199             }
200              
201 0     0   0 sub output {}
202 1     1   15 sub finalize {}
203              
204              
205             #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
206             #`,`, The String Consumer `,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
207             #```````````````````````````````````````````````````````````````````#
208              
209             package XML::SAX::Writer::StringConsumer;
210             $XML::SAX::Writer::StringConsumer::VERSION = '0.56';
211             @XML::SAX::Writer::StringConsumer::ISA = qw(XML::SAX::Writer::ConsumerInterface);
212              
213             #-------------------------------------------------------------------#
214             # new
215             #-------------------------------------------------------------------#
216             sub new {
217 4     4   47 my $self = shift->SUPER::new( @_ );
218 4         5 ${${$self}} = '';
  4         4  
  4         16  
219 4         9 return $self;
220             }
221             #-------------------------------------------------------------------#
222              
223             #-------------------------------------------------------------------#
224             # output
225             #-------------------------------------------------------------------#
226 7     7   682 sub output { ${${$_[0]}} .= $_[1] }
  7         5  
  7         21  
227             #-------------------------------------------------------------------#
228              
229             #-------------------------------------------------------------------#
230             # finalize
231             #-------------------------------------------------------------------#
232 3     3   5 sub finalize { ${$_[0]} }
  3         7  
233             #-------------------------------------------------------------------#
234              
235             #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
236             #`,`, The Code Consumer `,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
237             #```````````````````````````````````````````````````````````````````#
238              
239             package XML::SAX::Writer::CodeConsumer;
240             $XML::SAX::Writer::CodeConsumer::VERSION = '0.56';
241             @XML::SAX::Writer::CodeConsumer::ISA = qw(XML::SAX::Writer::ConsumerInterface );
242              
243             #-------------------------------------------------------------------#
244             # new
245             #-------------------------------------------------------------------#
246             sub new {
247 1     1   5 my $self = shift->SUPER::new( @_ );
248 1         7 $$self->( 'start_document', '' );
249 1         4 return $self;
250             }
251             #-------------------------------------------------------------------#
252              
253             #-------------------------------------------------------------------#
254             # output
255             #-------------------------------------------------------------------#
256 1     1   1 sub output { ${$_[0]}->('data', pop) } ## Avoid an extra copy
  1         3  
257             #-------------------------------------------------------------------#
258              
259             #-------------------------------------------------------------------#
260             # finalize
261             #-------------------------------------------------------------------#
262 1     1   2 sub finalize { ${$_[0]}->('end_document', '') }
  1         2  
263             #-------------------------------------------------------------------#
264              
265              
266             #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
267             #`,`, The Array Consumer ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
268             #```````````````````````````````````````````````````````````````````#
269              
270             package XML::SAX::Writer::ArrayConsumer;
271             $XML::SAX::Writer::ArrayConsumer::VERSION = '0.56';
272             @XML::SAX::Writer::ArrayConsumer::ISA = qw(XML::SAX::Writer::ConsumerInterface);
273              
274             #-------------------------------------------------------------------#
275             # new
276             #-------------------------------------------------------------------#
277             sub new {
278 2     2   365 my $self = shift->SUPER::new( @_ );
279 2         11 @$$self = ();
280 2         5 return $self;
281             }
282             #-------------------------------------------------------------------#
283              
284             #-------------------------------------------------------------------#
285             # output
286             #-------------------------------------------------------------------#
287 2     2   345 sub output { push @${$_[0]}, pop }
  2         6  
288             #-------------------------------------------------------------------#
289              
290             #-------------------------------------------------------------------#
291             # finalize
292             #-------------------------------------------------------------------#
293 1     1   3 sub finalize { return ${$_[0]} }
  1         3  
294             #-------------------------------------------------------------------#
295              
296              
297             #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
298             #`,`, The Handle Consumer `,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
299             #```````````````````````````````````````````````````````````````````#
300              
301             package XML::SAX::Writer::HandleConsumer;
302             $XML::SAX::Writer::HandleConsumer::VERSION = '0.56';
303             @XML::SAX::Writer::HandleConsumer::ISA = qw(XML::SAX::Writer::ConsumerInterface);
304              
305             #-------------------------------------------------------------------#
306             # output
307             #-------------------------------------------------------------------#
308             sub output {
309 4     4   736 my $fh = ${$_[0]};
  4         9  
310 4 50       37 print $fh pop or XML::SAX::Exception->throw(
311             Message => "Could not write to handle: $fh ($!)"
312             );
313             }
314             #-------------------------------------------------------------------#
315              
316             #-------------------------------------------------------------------#
317             # finalize
318             #-------------------------------------------------------------------#
319 0     0   0 sub finalize { return 0 }
320             #-------------------------------------------------------------------#
321              
322              
323             #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
324             #`,`, The File Consumer `,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
325             #```````````````````````````````````````````````````````````````````#
326              
327             package XML::SAX::Writer::FileConsumer;
328             $XML::SAX::Writer::FileConsumer::VERSION = '0.56';
329             @XML::SAX::Writer::FileConsumer::ISA = qw(XML::SAX::Writer::HandleConsumer);
330              
331             #-------------------------------------------------------------------#
332             # new
333             #-------------------------------------------------------------------#
334             sub new {
335 3     3   625 my ( $proto, $file ) = ( shift, shift );
336              
337 3 50 0     7 XML::SAX::Writer::Exception->throw(
338             Message => "No filename provided to " . ref( $proto || $proto )
339             ) unless defined $file;
340              
341 3         8 local *XFH;
342              
343 3 50       210 open XFH, ">$file" or XML::SAX::Writer::Exception->throw(
344             Message => "Error opening file $file: $!"
345             );
346              
347 3         28 return $proto->SUPER::new( *{XFH}{IO}, @_ );
348             }
349             #-------------------------------------------------------------------#
350              
351             #-------------------------------------------------------------------#
352             # finalize
353             #-------------------------------------------------------------------#
354             sub finalize {
355 2     2   6 close ${$_[0]};
  2         49  
356 2         5 return 0;
357             }
358             #-------------------------------------------------------------------#
359              
360              
361             #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
362             #`,`, Noop Converter ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
363             #```````````````````````````````````````````````````````````````````#
364              
365             package XML::SAX::Writer::NullConverter;
366             $XML::SAX::Writer::NullConverter::VERSION = '0.56';
367 4     4   413 sub new { return bless [], __PACKAGE__ }
368 3     3   8 sub convert { $_[1] }
369              
370              
371             #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
372             #`,`, Encode Converter ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
373             #```````````````````````````````````````````````````````````````````#
374              
375             package XML::SAX::Writer::Encode;
376             $XML::SAX::Writer::Encode::VERSION = '0.56';
377             sub new {
378 11     11   395 my ($class, $from, $to) = @_;
379 11         27 my $self = {
380             from_enc => $from,
381             to_enc => $to,
382             };
383 11         31 return bless $self, $class;
384             }
385             sub convert {
386 7     7   10 my ($self, $data) = @_;
387 7         8 eval {
388 7 50       34 $data = Encode::decode($self->{from_enc}, $data) if $self->{from_enc};
389 7 50       341 $data = Encode::encode($self->{to_enc}, $data, Encode::FB_CROAK) if $self->{to_enc};
390             };
391 7 100       244 if ($@) {
392 1         6 warn $@;
393 1         3 return;
394             }
395 6         8 return $data;
396             };
397              
398              
399             1;
400              
401             =pod
402              
403             =encoding UTF-8
404              
405             =head1 NAME
406              
407             XML::SAX::Writer - SAX2 XML Writer
408              
409             =head1 VERSION
410              
411             version 0.56
412              
413             =head1 SYNOPSIS
414              
415             use XML::SAX::Writer;
416             use XML::SAX::SomeDriver;
417              
418             my $w = XML::SAX::Writer->new;
419             my $d = XML::SAX::SomeDriver->new(Handler => $w);
420              
421             $d->parse('some options...');
422              
423             =head1 DESCRIPTION
424              
425             =head2 Why yet another XML Writer ?
426              
427             A new XML Writer was needed to match the SAX2 effort because quite
428             naturally no existing writer understood SAX2. My first intention had
429             been to start patching XML::Handler::YAWriter as it had previously
430             been my favourite writer in the SAX1 world.
431              
432             However the more I patched it the more I realised that what I thought
433             was going to be a simple patch (mostly adding a few event handlers and
434             changing the attribute syntax) was turning out to be a rewrite due to
435             various ideas I'd been collecting along the way. Besides, I couldn't
436             find a way to elegantly make it work with SAX2 without breaking the
437             SAX1 compatibility which people are probably still using. There are of
438             course ways to do that, but most require user interaction which is
439             something I wanted to avoid.
440              
441             So in the end there was a new writer. I think it's in fact better this
442             way as it helps keep SAX1 and SAX2 separated.
443              
444             =head1 METHODS
445              
446             =over 4
447              
448             =item * new(%hash)
449              
450             This is the constructor for this object. It takes a number of
451             parameters, all of which are optional.
452              
453             =item * Output
454              
455             This parameter can be one of several things. If it is a simple
456             scalar, it is interpreted as a filename which will be opened for
457             writing. If it is a scalar reference, output will be appended to this
458             scalar. If it is an array reference, output will be pushed onto this
459             array as it is generated. If it is a filehandle, then output will be
460             sent to this filehandle.
461              
462             Finally, it is possible to pass an object for this parameter, in which
463             case it is assumed to be an object that implements the consumer
464             interface L
465             INTERFACE>.
466              
467             If this parameter is not provided, then output is sent to STDOUT.
468              
469             =item * Escape
470              
471             This should be a hash reference where the keys are characters
472             sequences that should be escaped and the values are the escaped form
473             of the sequence. By default, this module will escape the ampersand
474             (&), less than (<), greater than (>), double quote ("), and apostrophe
475             ('). Note that some browsers don't support the ' escape used for
476             apostrophes so that you should be careful when outputting XHTML.
477              
478             If you only want to add entries to the Escape hash, you can first
479             copy the contents of %XML::SAX::Writer::DEFAULT_ESCAPE.
480              
481             =item * CommentEscape
482              
483             Comment content often needs to be escaped differently from other
484             content. This option works exactly as the previous one except that
485             by default it only escapes the double dash (--) and that the contents
486             can be copied from %XML::SAX::Writer::COMMENT_ESCAPE.
487              
488             =item * EncodeFrom
489              
490             The character set encoding in which incoming data will be provided.
491             This defaults to UTF-8, which works for US-ASCII as well.
492              
493             Set this to C if you do not wish to decode your data.
494              
495             =item * EncodeTo
496              
497             The character set encoding in which output should be encoded. Again,
498             this defaults to UTF-8.
499              
500             Set this to C if you do not with to encode your data.
501              
502             =item * QuoteCharacter
503              
504             Set the character used to quote attributes. This defaults to single quotes (')
505             for backwards compatibility.
506              
507             =back
508              
509             =head1 THE CONSUMER INTERFACE
510              
511             XML::SAX::Writer can receive pluggable consumer objects that will be
512             in charge of writing out what is formatted by this module. Setting a
513             Consumer is done by setting the Output option to the object of your
514             choice instead of to an array, scalar, or file handle as is more
515             commonly done (internally those in fact map to Consumer classes and
516             and simply available as options for your convenience).
517              
518             If you don't understand this, don't worry. You don't need it most of
519             the time.
520              
521             That object can be from any class, but must have two methods in its
522             API. It is also strongly recommended that it inherits from
523             XML::SAX::Writer::ConsumerInterface so that it will not break if that
524             interface evolves over time. There are examples at the end of
525             XML::SAX::Writer's code.
526              
527             The two methods that it needs to implement are:
528              
529             =over 4
530              
531             =item * output STRING
532              
533             (Required)
534              
535             This is called whenever the Writer wants to output a string formatted
536             in XML. Encoding conversion, character escaping, and formatting have
537             already taken place. It's up to the consumer to do whatever it wants
538             with the string.
539              
540             =item * finalize()
541              
542             (Optional)
543              
544             This is called once the document has been output in its entirety,
545             during the end_document event. end_document will in fact return
546             whatever finalize() returns, and that in turn should be returned
547             by parse() for whatever parser was invoked. It might be useful if
548             you need to provide feedback of some sort.
549              
550             =back
551              
552             Here's an example of a custom consumer. Note the extra C<$> signs in
553             front of $self; the base class is optimized for the overwhelmingly
554             common case where only one data member is required and $self is a
555             reference to that data member.
556              
557             package MyConsumer;
558              
559             @ISA = qw( XML::SAX::Writer::ConsumerInterface );
560              
561             use strict;
562              
563             sub new {
564             my $self = shift->SUPER::new( my $output );
565              
566             $$self = ''; # Note the extra '$'
567              
568             return $self;
569             }
570              
571             sub output {
572             my $self = shift;
573             $$self .= uc shift;
574             }
575              
576             sub get_output {
577             my $self = shift;
578             return $$self;
579             }
580              
581             And here is one way to use it:
582              
583             my $c = MyConsumer->new;
584             my $w = XML::SAX::Writer->new( Output => $c );
585              
586             ## ... send events to $w ...
587              
588             print $c->get_output;
589              
590             If you need to store more that one data member, pass in an array or hash
591             reference:
592              
593             my $self = shift->SUPER::new( {} );
594              
595             and access it like:
596              
597             sub output {
598             my $self = shift;
599             $$self->{Output} .= uc shift;
600             }
601              
602             =head1 THE ENCODER INTERFACE
603              
604             Encoders can be plugged in to allow one to use one's favourite encoder
605             object. Presently there are two encoders: Encode and NullEncoder. They
606             need to implement two methods, and may inherit from
607             XML::SAX::Writer::NullConverter if they wish to
608              
609             =over 4
610              
611             =item new FROM_ENCODING, TO_ENCODING
612              
613             Creates a new Encoder. The arguments are the chosen encodings.
614              
615             =item convert STRING
616              
617             Converts that string and returns it.
618              
619             =back
620              
621             Note that the return value of the convert method is B checked. Output may
622             be truncated if a character couldn't be converted correctly. To avoid problems
623             the encoder should take care encoding errors itself, for example by raising an
624             exception.
625              
626             =head1 CUSTOM OUTPUT
627              
628             This module is generally used to write XML -- which it does most of the
629             time -- but just like the rest of SAX it can be used as a generic
630             framework to output data, the opposite of a non-XML SAX parser.
631              
632             Of course there's only so much that one can abstract, so depending on
633             your format this may or may not be useful. If it is, you'll need to
634             know the following API (and probably to have a look inside
635             C, the default Writer).
636              
637             =over
638              
639             =item init
640              
641             Called before the writing starts, it's a chance for the subclass to do
642             some initialisation if it needs it.
643              
644             =item setConverter
645              
646             This is used to set the proper converter for character encodings. The
647             default implementation should suffice but you can override it. It must
648             set C<< $self->{Encoder} >> to an Encoder object. Subclasses *should* call
649             it.
650              
651             =item setConsumer
652              
653             Same as above, except that it is for the Consumer object, and that it
654             must set C<< $self->{Consumer} >>.
655              
656             =item setEscaperRegex
657              
658             Will initialise the escaping regex C<< $self->{EscaperRegex} >> based on
659             what is needed.
660              
661             =item escape STRING
662              
663             Takes a string and escapes it properly.
664              
665             =item setCommentEscaperRegex and escapeComment STRING
666              
667             These work exactly the same as the two above, except that they are meant
668             to operate on comment contents, which often have different escaping rules
669             than those that apply to regular content.
670              
671             =back
672              
673             =head1 TODO
674              
675             - proper UTF-16 handling
676              
677             - the formatting options need to be developed.
678              
679             - test, test, test (and then some tests)
680              
681             - doc, doc, doc (actually this part is in better shape)
682              
683             - remove the xml_decl and replace it with intelligent logic, as
684             discussed on perl-xml
685              
686             - make a the Consumer selecting code available in the API, to avoid
687             duplicating
688              
689             - add an Apache output Consumer, triggered by passing $r as Output
690              
691             =head1 CREDITS
692              
693             Michael Koehne (XML::Handler::YAWriter) for much inspiration and Barrie
694             Slaymaker for the Consumer pattern idea, the coderef output option and
695             miscellaneous bugfixes and performance tweaks. Of course the usual
696             suspects (Kip Hampton and Matt Sergeant) helped in the usual ways.
697              
698             =head1 SEE ALSO
699              
700             XML::SAX::*
701              
702             =head1 AUTHORS
703              
704             =over 4
705              
706             =item *
707              
708             Robin Berjon
709              
710             =item *
711              
712             Chris Prather
713              
714             =back
715              
716             =head1 COPYRIGHT AND LICENSE
717              
718             This software is copyright (c) 2014 by Robin Berjon.
719              
720             This is free software; you can redistribute it and/or modify it under
721             the same terms as the Perl 5 programming language system itself.
722              
723             =cut
724              
725             __END__