File Coverage

blib/lib/XML/Genx/SAXWriter.pm
Criterion Covered Total %
statement 99 101 98.0
branch 21 24 87.5
condition 8 17 47.0
subroutine 24 24 100.0
pod 10 10 100.0
total 162 176 92.0


line stmt bran cond sub pod time code
1             package XML::Genx::SAXWriter;
2              
3 2     2   55957 use strict;
  2         5  
  2         83  
4 2     2   11 use warnings;
  2         6  
  2         67  
5              
6 2     2   11 use Carp ();
  2         4  
  2         31  
7 2     2   1968 use XML::Genx::Simple;
  2         7  
  2         58  
8              
9 2     2   16 use base 'XML::SAX::Base';
  2         4  
  2         4331  
10              
11             our $VERSION = '0.22';
12              
13             sub new {
14 8     8 1 4581 my $class = shift;
15 8         22 my $self = bless {}, $class;
16 8         20 $self->_init( @_ );
17 8         22 return $self;
18             }
19              
20             sub _init {
21 8     8   11 my $self = shift;
22 8         18 my %opt = @_;
23 8   100     41 $self->_out( $opt{ out } || \*STDOUT );
24 8         13 return;
25             }
26              
27             sub start_document {
28 7     7 1 34 my $self = shift;
29              
30 7         4398 $self->_w( XML::Genx::Simple->new );
31              
32 7 100 33     24 if ( ref $self->_out eq 'SCALAR' ) {
    100 33        
    100          
    50          
    50          
33 4         9 $self->_w->StartDocString;
34             } elsif ( ref $self->_out eq 'GLOB' ) {
35 1         4 $self->_w->StartDocFile( $self->_out );
36             } elsif ( ref $self->_out eq 'CODE' ) {
37 1         3 $self->_w->StartDocSender( $self->_out );
38             } elsif ( ref $self->_out && $self->_out->isa( 'IO::Handle' ) ) {
39 0         0 $self->_w->StartDocFile( $self->_out );
40             } elsif ( defined $self->_out && length $self->_out ) {
41 1 50       5 open( my $fh, '>', $self->_out )
42             or Carp::croak( "open(".$self->_out."): $!" );
43 1         74 $self->_w->StartDocFile( $fh );
44             } else {
45 0         0 Carp::croak( "start_document: no output specified!" );
46             }
47             }
48              
49             sub end_document {
50 7     7 1 30 my $self = shift;
51 7         13 my $rv = $self->_w->EndDocument;
52 7 100       21 if ( ref $self->_out eq 'SCALAR' ) {
53 4         7 ${ $self->_out } = $self->_w->GetDocString;
  4         7  
54             }
55 7         40 return $rv;
56             }
57              
58             sub start_element {
59 8     8 1 61 my $self = shift;
60 8         12 my ( $data ) = @_;
61              
62             my $ns =
63 8         19 $self->_new_namespace( $data->{ NamespaceURI }, $data->{ Prefix } );
64 8         20 $self->_new_element( $ns, $data->{ LocalName } )->StartElement;
65              
66 8         22 while ( my $ns = $self->_pop_ns ) {
67             # In order to get default namespaces done correctly, we have to
68             # specify the prefix explicitly to AddNamespace(). See comments
69             # above _declare_namespace().
70 4         6 my ( $uri, $prefix ) = @$ns;
71 4         6 $self->_new_namespace( $uri, $prefix )->AddNamespace( $prefix );
72             }
73              
74 8 100       9 foreach ( values %{ $data->{ Attributes } || {} } ) {
  8         42  
75 3         9 my $ns = $self->_new_namespace( $_->{ NamespaceURI }, $_->{ Prefix } );
76             $self->_new_attribute( $ns, $_->{ LocalName } )
77 3         7 ->AddAttribute( $_->{ Value } );
78             }
79              
80 8         19 return;
81             }
82              
83             sub characters {
84 6     6 1 26 my $self = shift;
85 6         9 my ( $data ) = @_;
86 6         10 $self->_w->AddText( $data->{ Data } );
87             }
88              
89             sub end_element {
90 8     8 1 40 my $self = shift;
91 8         9 my ( $data ) = @_;
92 8         14 $self->_w->EndElement;
93             }
94              
95             sub start_prefix_mapping {
96 4     4 1 49 my $self = shift;
97 4         6 my ( $data ) = @_;
98 4         13 $self->_push_ns( $data->{ NamespaceURI }, $data->{ Prefix } );
99             }
100              
101             sub end_prefix_mapping {
102 4     4 1 13 my $self = shift;
103 4         16 my ( $data ) = @_;
104             # XXX Do we need to do anything here? I don't think so.
105             }
106              
107             sub processing_instruction {
108 1     1 1 12 my $self = shift;
109 1         2 my ( $data ) = @_;
110 1         3 $self->_w->PI( $data->{ Target }, $data->{ Data } );
111             }
112              
113             sub comment {
114 1     1 1 10 my $self = shift;
115 1         2 my ( $data ) = @_;
116 1         4 $self->_w->Comment( $data->{ Data } );
117             }
118              
119             #---------------------------------------------------------------------
120             # PRIVATE
121             #---------------------------------------------------------------------
122              
123             sub _w {
124 56     56   67 my $self = shift;
125 56 100       86 if ( @_ ) {
126 7         14 $self->{ _w } = $_[0];
127 7         11 return $self;
128             } else {
129 49         638 return $self->{ _w };
130             }
131             }
132              
133             sub _out {
134 37     37   40 my $self = shift;
135 37 100       66 if ( @_ ) {
136 8         22 $self->{ _out } = $_[0];
137 8         13 return $self;
138             } else {
139 29         230 return $self->{ _out };
140             }
141             }
142              
143             sub _push_ns {
144 4     4   6 my $self = shift;
145 4         6 my ( $ns, $prefix ) = @_;
146 4         5 push @{ $self->{ nstodo } }, [$ns, $prefix];
  4         16  
147 4         9 return;
148             }
149              
150             sub _pop_ns {
151 12     12   13 my $self = shift;
152 12         19 return pop @{ $self->{ nstodo } };
  12         44  
153             }
154              
155             # Return a declared namespace object if it's present. If no namespace
156             # is given, return undef.
157             sub _new_namespace {
158 15     15   17 my $self = shift;
159 15         17 my ( $nsuri, $prefix ) = @_;
160 15 100       40 return unless $nsuri;
161 8   66     46 return $self->{ namespace }{ $nsuri } ||=
162             $self->_declare_namespace( $nsuri, $prefix );
163             }
164              
165             # Get Genx to give us a new namespace object. NB: If a default
166             # namespace is requested, we ask Genx to assign an autogenerated prefix
167             # instead. This gets countered further up in start_element(). When we
168             # call AddNamespace(), we pass in the requested prefix instead, which
169             # will be "" in case of the default namespace. This is all in order to
170             # work around Genx, which will not let you declare two namespaces with
171             # the default prefix.
172             sub _declare_namespace {
173 4     4   4 my $self = shift;
174 4         6 my ( $nsuri, $prefix ) = @_;
175 4 100       8 if ( $prefix ) {
176 1         2 return $self->_w->DeclareNamespace( $nsuri, $prefix );
177             } else {
178 3         8 return $self->_w->DeclareNamespace( $nsuri );
179             }
180             }
181              
182             sub _new_element {
183 8     8   10 my $self = shift;
184 8         15 my ( $ns, $lname ) = @_;
185 8   33     57 return $self->{ element }{ $lname } ||=
186             $self->_w->DeclareElement( $ns, $lname );
187             }
188              
189             sub _new_attribute {
190 3     3   3 my $self = shift;
191 3         5 my ( $ns, $lname ) = @_;
192 3   33     22 return $self->{ attribute }{ $lname } ||=
193             $self->_w->DeclareAttribute( $ns, $lname );
194             }
195              
196             1;
197             __END__