File Coverage

blib/lib/XML/Generator/PerlData.pm
Criterion Covered Total %
statement 327 498 65.6
branch 117 220 53.1
condition 36 56 64.2
subroutine 29 39 74.3
pod 26 30 86.6
total 535 843 63.4


line stmt bran cond sub pod time code
1             package XML::Generator::PerlData;
2              
3 10     10   258446 use strict;
  10         1273  
  10         408  
4 10     10   22769 use XML::SAX::Base;
  10         346110  
  10         442  
5 10     10   134 use vars qw($VERSION @ISA $NS_XMLNS $NS_XML);
  10         27  
  10         968  
6 10     10   12896 use Data::Dumper;
  10         98049  
  10         62737  
7             # some globals
8             $VERSION = '0.91';
9             @ISA = qw( XML::SAX::Base );
10             $NS_XML = 'http://www.w3.org/XML/1998/namespace';
11             $NS_XMLNS = 'http://www.w3.org/2000/xmlns/';
12              
13             sub new {
14 9     9 1 231 my $proto = shift;
15 9         131 my $self = $proto->SUPER::new( @_ );
16              
17 9         830 my %args = @_;
18              
19 9 100       39 delete $args{Handler} if defined $args{Handler};
20              
21 9         61 $self->{Namespaces} = { $NS_XMLNS => 'xmlns',
22             $NS_XML => 'xml'
23             };
24 9         41 $self->{DeclaredNamespaces} = {$NS_XMLNS => 'xmlns',
25             $NS_XML => 'xml'
26             };
27              
28 9         27 $self->{InScopeNamespaceStack} = [];
29              
30             # _Parents needed for attribute vs. element fixing;
31 9         23 $self->{_Parents} = [];
32              
33 9         54 $self->init( %args );
34 9         29 return $self;
35             }
36              
37             sub init {
38 12     12 1 23 my $self = shift;
39 12         28 my %args = @_;
40              
41 12 100       44 $self->{Keymap} = $args{keymap} if defined $args{keymap};
42 12 50       54 $self->{RootName} = $args{rootname} if defined $args{rootname};
43 12 50       42 $self->{SkipRoot} = $args{skiproot} if defined $args{skiproot};
44 12 50       39 $self->{DefaultElementName} = $args{defaultname} if defined $args{defaultname};
45 12 50       39 $self->{BindAttrs} = 1 if defined $args{bindattrs};
46 12   100     71 $self->{Keymap} ||= {};
47 12   100     120 $self->{RootName} ||= 'document';
48 12   100     76 $self->{DefaultElementName} ||= 'default';
49 12   100     61 $self->{TokenReplacementChar} ||= '_';
50              
51 12 50       58 if ( defined $args{namespaces} ) {
52 0         0 foreach my $uri ( keys( %{$args{namespaces}} )) {
  0         0  
53 0         0 $self->{Namespaces}->{"$uri"} = $args{namespaces}->{"$uri"};
54             }
55             }
56              
57             # let 'em change handlers if they want.
58 12 50       65 if ( defined $args{Handler} ) {
59 0         0 $self->set_handler( $args{Handler} );
60             }
61              
62              
63              
64 12 100       42 if ( defined( $args{attrmap} ) ) {
65 1         2 $self->{Attrmap} = {};
66 1         3 while ( my ($k, $v) = ( each( %{$args{attrmap}} ) )) {
  2         31  
67 1 50       2 push @{$self->{Attrmap}->{$k}}, ref( $v ) ? @{$v} : $v;
  1         6  
  1         3  
68             }
69             }
70 12   100     59 $self->{Attrmap} ||= {};
71              
72 12 100       56 if ( defined( $args{namespacemap} ) ) {
73 2         5 $self->{Namespacemap} = {};
74 2         4 while ( my ($k, $v) = ( each( %{$args{namespacemap}} ) )) {
  6         38  
75 4 100       6 push @{$self->{Namespacemap}->{$k}}, ref( $v ) ? @{$v} : $v;
  4         22  
  2         5  
76             }
77             }
78 12   100     82 $self->{Namespacemap} ||= {};
79              
80 12 50       40 if ( defined( $args{charmap} ) ) {
81 0         0 $self->{Charmap} = {};
82 0         0 while ( my ($k, $v) = ( each( %{$args{charmap}} ) )) {
  0         0  
83 0 0       0 push @{$self->{Charmap}->{$k}}, ref( $v ) ? @{$v} : $v;
  0         0  
  0         0  
84             }
85             }
86 12   100     84 $self->{Charmap} ||= {};
87              
88             # Skipelements:
89             # Makes sense from an interface standpoint for the user
90             # to pass an array ref, but it makes it more efficient to
91             # implement if its a hash ref. Let's pull a little juju.
92              
93 12         24 my %skippers = ();
94 12 100       69 if ( $args{skipelements} ) {
95 1         2 %skippers = map { $_, 1} @{$args{skipelements}}
  1         3  
  1         2  
96             }
97              
98             #warn "SKIPPPERS " . Dumper( \%args );
99 12         40 $self->{Skipelements} = \%skippers;
100              
101             }
102              
103             sub parse_start {
104 3     3 1 7 my $self = shift;
105 3 50       11 $self->init( @_ ) if scalar @_;
106              
107 3         32 $self->start_document( {} );
108              
109 3 50       214 unless ( defined $self->{SkipRoot} ) {
110 3         14 $self->start_element( $self->_start_details( $self->{RootName} ) );
111 3         180 push @{$self->{_Parents}}, $self->{RootName};
  3         14  
112             }
113             }
114              
115             sub parse_end {
116 3     3 1 6 my $self = shift;
117 3 50       25 unless ( defined $self->{SkipRoot} ) {
118 3         11 $self->end_element( $self->_end_details( $self->{RootName} ) );
119             }
120            
121 3         782 foreach my $uri ( keys( %{$self->{DeclaredNamespaces}} )) {
  3         13  
122 10 100       80 next if $uri eq $NS_XMLNS;
123 7 100       26 next if $uri eq $NS_XML;
124 4 50       10 next if not defined $self->{DeclaredNamespaces}->{$uri};
125              
126 4         36 $self->end_prefix_mapping({ Prefix => $self->{DeclaredNamespaces}->{$uri},
127             NamespaceURI => $uri
128             });
129             }
130              
131 3         96 return $self->end_document();
132             }
133              
134             sub parse {
135 3     3 1 42 my $self = shift;
136 3   50     16 my $wtf = shift || die "No Data Passed!";
137 3         30 $self->init( @_ );
138              
139 3         15 my $type = $self->get_type( $wtf );
140 3 50       18 if ( defined $type ) {
141 3         11 my $processor = lc( $type ) . 'ref2SAX';
142             # process the document...
143 3         18 $self->parse_start;
144 3         33 $self->$processor( $wtf );
145 3         64 $self->parse_end;
146             }
147             else {
148 0         0 die "Data passed must be a reference.";
149             }
150             }
151              
152             sub parse_chunk {
153 0     0 1 0 my $self = shift;
154 0   0     0 my $wtf = shift || die "No Data Passed!";
155 0         0 my $type = $self->get_type( $wtf );
156 0 0       0 if ( defined $type ) {
157 0         0 my $processor = lc( $type ) . 'ref2SAX';
158 0         0 $self->$processor( $wtf );
159             }
160             else {
161 0         0 die "Data passed must be a reference.";
162             }
163             }
164              
165              
166             sub hashref2SAX {
167 10     10 0 23 my $self = shift;
168 10         11 my $hashref= shift;
169              
170 10         14 my $char_data = '';
171              
172 10         28 ELEMENT: foreach my $key (keys (%{$hashref} )) {
  10         29  
173 22         208 my $value = $hashref->{$key};
174 22         48 my $element_name = $self->_keymapped_name( $key );
175            
176 22 100       64 next if defined $self->{Skipelements}->{$element_name};
177              
178            
179 21 100 66     118 if ( defined $self->{_Parents}->[-1] and defined $self->{Attrmap}->{$self->{_Parents}->[-1]} ) {
180 3         5 foreach my $name ( @{$self->{Attrmap}->{$self->{_Parents}->[-1]}} ) {
  3         17  
181 5 100       19 next ELEMENT if $name eq $element_name;
182             }
183             }
184              
185 19 50 33     118 if ( defined $self->{_Parents}->[-1] and defined $self->{Charmap}->{$self->{_Parents}->[-1]} ) {
186 0 0       0 if ( grep {$_ eq $element_name} @{$self->{Charmap}->{$self->{_Parents}->[-1]}} ) {
  0         0  
  0         0  
187 0         0 $self->characters( {Data => $value });
188 0         0 next ELEMENT;
189             }
190             }
191              
192 19         42 my $type = $self->get_type( $value );
193              
194 19 100       57 if ( $type eq 'ARRAY' ) {
    100          
195 4         5 push @{$self->{_Parents}}, $element_name;
  4         8  
196 4         11 $self->arrayref2SAX( $value );
197 4         9 pop (@{$self->{_Parents}});
  4         28  
198             }
199             elsif ( $type eq 'HASH' ) {
200             # attr mojo
201 7         11 my %attrs = ();
202 7 100       22 if ( defined $self->{Attrmap}->{$element_name} ) {
203 1         3 my @attr_names = ();
204 1         2 ATTR: foreach my $child ( keys( %{$value} )) {
  1         3  
205 3         6 my $name = $self->_keymapped_name( $child );
206 3 100       3 if ( grep {$_ eq $name} @{$self->{Attrmap}->{$element_name}} ) {
  6         17  
  3         7  
207 2 50       6 if ( ref( $value->{$child} ) ) {
208 0         0 warn "Cannot use a reference value " . $value->{$child} . " for key '$child' as XML attribute\n";
209 0         0 next ATTR;
210             }
211              
212 2         7 $attrs{$name} = $value->{$child};
213             }
214             }
215             }
216 7         19 $self->start_element( $self->_start_details( $element_name, \%attrs ) );
217 7         115 push @{$self->{_Parents}}, $element_name;
  7         18  
218 7         50 $self->hashref2SAX( $value );
219 7         113 pop (@{$self->{_Parents}});
  7         47  
220 7         46 $self->end_element( $self->_end_details( $element_name ) );
221             }
222             else {
223 8         23 $self->start_element( $self->_start_details( $element_name ) );
224 8         167 $self->characters( {Data => $value} );
225 8         188 $self->end_element( $self->_end_details( $element_name ) );
226             }
227             }
228             }
229              
230             sub arrayref2SAX {
231 7     7 0 11 my $self = shift;
232 7         14 my $arrayref= shift;
233 7   33     31 my $passed_name = shift || $self->{_Parents}->[-1];
234 7         15 my $temp_name = $self->_keymapped_name( $passed_name );
235              
236 7         10 my $element_name;
237             my $i;
238              
239 7         13 ELEMENT: for ( $i = 0; $i < @{$arrayref}; $i++ ) {
  28         413  
240 21 100       39 if ( ref( $temp_name ) eq 'ARRAY' ) {
241 3   33     9 my $ntest = $temp_name->[$i] || $self->{DefaultElementName};
242 3 50       13 if ( ref( $ntest ) eq 'CODE' ) {
243 0         0 $element_name = &{$ntest}();
  0         0  
244             }
245             else {
246 3         7 $element_name = $self->_keymapped_name( $ntest );
247             }
248             }
249             else {
250 18         28 $element_name = $temp_name;
251             }
252              
253              
254 21 50       53 next if defined $self->{Skipelements}->{$element_name};
255            
256              
257 21         47 my $type = $self->get_type( $arrayref->[$i] );
258              
259 21         29 my $value = $arrayref->[$i];
260              
261 21 100       47 if ( $type eq 'ARRAY' ) {
    50          
262 3         5 push @{$self->{_Parents}}, $element_name;
  3         6  
263 3         12 $self->arrayref2SAX( $value );
264 3         14 pop (@{$self->{_Parents}});
  3         17  
265             }
266             elsif ( $type eq 'HASH' ) {
267             # attr mojo
268 0         0 my %attrs = ();
269 0 0       0 if ( defined $self->{Attrmap}->{$element_name} ) {
270 0         0 my @attr_names = ();
271 0         0 ATTR: foreach my $child ( keys( %{$value} )) {
  0         0  
272 0         0 my $name = $self->_keymapped_name( $child );
273 0 0       0 if ( grep {$_ eq $name} @{$self->{Attrmap}->{$element_name}} ) {
  0         0  
  0         0  
274 0 0       0 if ( ref( $value->{$child} ) ) {
275 0         0 warn "Cannot use a reference value " . $value->{$child} . " for key '$child' as XML attribute\n";
276 0         0 next ATTR;
277             }
278            
279 0         0 $attrs{$name} = $value->{$child};
280             }
281             }
282             }
283 0         0 $self->start_element( $self->_start_details( $element_name, \%attrs ) );
284 0         0 push @{$self->{_Parents}}, $element_name;
  0         0  
285 0         0 $self->hashref2SAX( $arrayref->[$i] );
286 0         0 pop (@{$self->{_Parents}});
  0         0  
287 0         0 $self->end_element( $self->_end_details( $element_name ) );
288             }
289             else {
290 18         33 $self->start_element( $self->_start_details( $element_name ) );
291 18         345 $self->characters( {Data => $arrayref->[$i]} );
292 18         339 $self->end_element( $self->_end_details( $element_name ) );
293             }
294             }
295             }
296              
297             sub get_type {
298 43     43 0 58 my $self = shift;
299 43         47 my $wtf = shift;
300              
301 43         69 my $type = ref( $wtf );
302 43 100       68 if ( $type ) {
303 17 100 100     90 if ( $type eq 'ARRAY' or $type eq 'HASH' or $type eq 'SCALAR') {
      66        
304 15         39 return $type;
305             }
306             else {
307             # we were passed an object, yuk.
308             # props to barrie slaymaker for the tip here... mine was much fuglier. ;-)
309 2 50       18 if ( UNIVERSAL::isa( $wtf, "HASH" ) ) {
    0          
    0          
310 2         6 return 'HASH';
311             }
312             elsif ( UNIVERSAL::isa( $wtf, "ARRAY" ) ) {
313 0         0 return 'ARRAY';
314             }
315             elsif ( UNIVERSAL::isa( $wtf, "SCALAR" ) ) {
316 0         0 return 'SCALAR';
317             }
318             else {
319 0         0 die "Unhandlable reference passed: $type \n";
320             }
321             }
322              
323             }
324             else {
325 26         52 return '_plain';
326             }
327             }
328              
329             ###
330             # Interface helpers
331             ###
332              
333             sub add_namespace {
334 4     4 1 19 my $self = shift;
335 4         14 my %args = @_;
336 4 50 33     31 unless ( defined $args{prefix} and defined $args{uri} ) {
337 0         0 warn "Invalid arguments passed to add_namespace, skipping.";
338 0         0 return;
339             }
340 4         17 $self->{Namespaces}->{"$args{uri}"} = $args{prefix};
341             }
342              
343             sub namespacemap {
344 9     9 1 362 my $self = shift;
345 9         11 my %nsmap;
346 9 100       21 if ( scalar( @_ ) > 0 ) {
347 1 50       4 if ( ref( $_[0] )) {
348 0         0 %nsmap = %{$_[0]};
  0         0  
349             }
350             else {
351 1         4 %nsmap = @_;
352             }
353              
354 1         5 while ( my ($k, $v) = each ( %nsmap ) ) {
355 3 50       6 if ( ref( $v ) ) {
356 0         0 $self->{Namespacemap}->{$k} = $v;
357             }
358             else {
359 3         38 $self->{Namespacemap}->{$k} = [ $v ];
360             }
361             }
362             }
363            
364 9 100       41 return wantarray ? %{$self->{Namespacemap}} : $self->{Namespacemap};
  2         13  
365             }
366              
367             sub add_namespacemap {
368 2     2 1 5 my $self = shift;
369 2         6 my %args = @_;
370              
371 2         5 foreach my $uri ( keys( %args )) {
372 2         2 push @{$self->{Namespacemap}->{"$uri"}}, $args{$uri};
  2         12  
373             }
374             }
375              
376             sub delete_namespacemap {
377 2     2 0 496 my $self = shift;
378 2         3 my @mapped;
379 2 50       13 if ( scalar( @_ ) > 0 ) {
380 2 50       6 if ( ref( $_[0] )) {
381 0         0 @mapped = @{$_[0]};
  0         0  
382             }
383             else {
384 2         5 @mapped = @_;
385             }
386 2         9 foreach my $name ( @mapped ) {
387 2         3 foreach my $uri ( keys( %{$self->{Namespacemap}} )) {
  2         7  
388 8         8 my $i;
389 8         12 for ($i = 0; $i < scalar @{$self->{Namespacemap}->{$uri}}; $i++) {
  16         37  
390 8 100       22 splice @{$self->{Namespacemap}->{$uri}}, $i, 1 if $self->{Namespacemap}->{$uri}->[$i] eq $name;
  2         5  
391             }
392 8 100       10 delete $self->{Namespacemap}->{$uri} unless scalar @{$self->{Namespacemap}->{$uri}} > 0;
  8         29  
393             }
394             }
395             }
396             }
397              
398             sub attrmap {
399 7     7 1 349 my $self = shift;
400 7         8 my %attrmap;
401 7 100       16 if ( scalar( @_ ) > 0 ) {
402 1 50       14 if ( ref( $_[0] )) {
403 0         0 %attrmap = %{$_[0]};
  0         0  
404             }
405             else {
406 1         5 %attrmap = @_;
407             }
408            
409 1         5 while ( my ($k, $v) = each( %attrmap )) {
410 3 50       6 if ( ref( $v ) ) {
411 0         0 $self->{Attrmap}->{$k} = $v;
412             }
413             else {
414 3         35 $self->{Attrmap}->{$k} = [ $v ];
415             }
416             }
417             }
418            
419 7 100       30 return wantarray ? %{$self->{Attrmap}} : $self->{Attrmap};
  2         13  
420             }
421              
422             sub add_attrmap {
423 1     1 1 2 my $self = shift;
424 1         2 my %attrmap;
425 1 50       4 if ( scalar( @_ ) > 0 ) {
426 1 50       4 if ( ref( $_[0] )) {
427 0         0 %attrmap = %{$_[0]};
  0         0  
428             }
429             else {
430 1         3 %attrmap = @_;
431             }
432              
433 1         6 while ( my ($k, $v) = each ( %attrmap ) ) {
434 1 50       2 if ( ref( $v ) ) {
435 0         0 $self->{Attrmap}->{$k} = $v;
436             }
437             else {
438 1         7 $self->{Attrmap}->{$k} = [ $v ];
439             }
440             }
441            
442             }
443             }
444              
445             sub delete_attrmap {
446 1     1 1 327 my $self = shift;
447 1         2 my @mapped;
448 1 50       5 if ( scalar( @_ ) > 0 ) {
449 1 50       10 if ( ref( $_[0] )) {
450 0         0 @mapped = @{$_[0]};
  0         0  
451             }
452             else {
453 1         3 @mapped = @_;
454             }
455 1         2 foreach my $name ( @mapped ) {
456 1 50       14 delete $self->{Attrmap}->{$name} if $self->{Attrmap}->{$name};
457             }
458             }
459             }
460              
461             sub charmap {
462 0     0 1 0 my $self = shift;
463 0         0 my %charmap;
464 0 0       0 if ( scalar( @_ ) > 0 ) {
465 0 0       0 if ( ref( $_[0] )) {
466 0         0 %charmap = %{$_[0]};
  0         0  
467             }
468             else {
469 0         0 %charmap = @_;
470             }
471            
472 0         0 while ( my ($k, $v) = each( %charmap )) {
473 0 0       0 if ( ref( $v ) ) {
474 0         0 $self->{Charmap}->{$k} = $v;
475             }
476             else {
477 0         0 $self->{Charmap}->{$k} = [ $v ];
478             }
479             }
480             }
481            
482 0 0       0 return wantarray ? %{$self->{Charmap}} : $self->{Charmap};
  0         0  
483             }
484              
485             sub add_charmap {
486 0     0 1 0 my $self = shift;
487 0         0 my %charmap;
488 0 0       0 if ( scalar( @_ ) > 0 ) {
489 0 0       0 if ( ref( $_[0] )) {
490 0         0 %charmap = %{$_[0]};
  0         0  
491             }
492             else {
493 0         0 %charmap = @_;
494             }
495              
496 0         0 while ( my ($k, $v) = each ( %charmap ) ) {
497 0 0       0 if ( ref( $v ) ) {
498 0         0 $self->{Charmap}->{$k} = $v;
499             }
500             else {
501 0         0 $self->{Charmap}->{$k} = [ $v ];
502             }
503             }
504            
505             }
506             }
507              
508             sub delete_charmap {
509 0     0 1 0 my $self = shift;
510 0         0 my @mapped;
511 0 0       0 if ( scalar( @_ ) > 0 ) {
512 0 0       0 if ( ref( $_[0] )) {
513 0         0 @mapped = @{$_[0]};
  0         0  
514             }
515             else {
516 0         0 @mapped = @_;
517             }
518 0         0 foreach my $name ( @mapped ) {
519 0 0       0 delete $self->{Charmap}->{$name} if $self->{Charmap}->{$name};
520             }
521             }
522             }
523              
524             sub add_keymap {
525 2     2 1 15 my $self = shift;
526 2         4 my %keymap;
527 2 50       7 if ( scalar( @_ ) > 0 ) {
528 2 50       6 if ( ref( $_[0] )) {
529 0         0 %keymap = %{$_[0]};
  0         0  
530             }
531             else {
532 2         6 %keymap = @_;
533             }
534              
535 2         6 foreach my $name ( keys( %keymap )) {
536 2         9 $self->{Keymap}->{$name} = $keymap{$name};
537             }
538             }
539             }
540              
541             sub delete_keymap {
542 1     1 1 353 my $self = shift;
543 1         3 my @mapped;
544 1 50       4 if ( scalar( @_ ) > 0 ) {
545 1 50       3 if ( ref( $_[0] )) {
546 0         0 @mapped = @{$_[0]};
  0         0  
547             }
548             else {
549 1         3 @mapped = @_;
550             }
551 1         2 foreach my $name ( @mapped ) {
552 1 50       7 delete $self->{Keymap}->{$name} if $self->{Keymap}->{$name};
553             }
554             }
555             }
556              
557             sub add_skipelements {
558 0     0 1 0 my $self = shift;
559 0         0 my @skippers;
560 0 0       0 if ( scalar( @_ ) > 0 ) {
561 0 0       0 if ( ref( $_[0] )) {
562 0         0 @skippers = @{$_[0]};
  0         0  
563             }
564             else {
565 0         0 @skippers = @_;
566             }
567 0         0 foreach my $name ( @skippers ) {
568 0         0 $self->{Skipelements}->{$name} = 1;
569             }
570             }
571             }
572              
573             sub delete_skipelements {
574 0     0 1 0 my $self = shift;
575 0         0 my @skippers;
576 0 0       0 if ( scalar( @_ ) > 0 ) {
577 0 0       0 if ( ref( $_[0] )) {
578 0         0 @skippers = @{$_[0]};
  0         0  
579             }
580             else {
581 0         0 @skippers = @_;
582             }
583 0         0 foreach my $name ( @skippers ) {
584 0 0       0 delete $self->{Skipelements}->{$name} if $self->{Skipelements}->{$name};
585             }
586             }
587             }
588              
589             sub rootname {
590 3     3 1 10 my ($self, $rootname) = @_;
591            
592             # ubu: add a check to warn them if the processing has already begun?
593 3 100       7 if ( defined $rootname ) {
594 1         2 $self->{RootName} = $rootname;
595             }
596              
597 3         12 return $self->{RootName};
598             }
599              
600             sub bindattrs {
601 0     0 1 0 my $self = shift;
602 0         0 my $flag = shift;
603 0 0       0 if ( defined($flag) ) {
604 0 0       0 if ($flag == 0) {
605 0         0 $self->{BindAttrs} = undef;
606             }
607             else {
608 0         0 $self->{BindAttrs} = 1;
609             }
610             }
611              
612 0         0 return $self->{BindAttrs};
613              
614             }
615              
616             sub defaultname {
617 3     3 1 10 my ($self, $dname) = @_;
618              
619 3 100       7 if ( defined $dname ) {
620 1         3 $self->{DefaultElementName} = $dname;
621             }
622 3         13 return $self->{DefaultElementName};
623             }
624            
625             sub keymap {
626 7     7 1 336 my $self = shift;
627 7         7 my %keymap;
628 7 100       17 if ( scalar( @_ ) > 0 ) {
629 1 50       4 if ( ref( $_[0] )) {
630 0         0 %keymap = %{$_[0]};
  0         0  
631             }
632             else {
633 1         4 %keymap = @_;
634             }
635 1         3 $self->{Keymap} = \%keymap;
636             }
637              
638 7 100       31 return wantarray ? %{$self->{Keymap}} : $self->{Keymap};
  2         13  
639             }
640              
641             sub skipelements {
642 0     0 1 0 my $self = shift;
643 0         0 my @skippers;
644 0 0       0 if ( scalar( @_ ) > 0 ) {
645 0 0       0 if ( ref( $_[0] )) {
646 0         0 @skippers = @{$_[0]};
  0         0  
647             }
648             else {
649 0         0 @skippers = @_;
650             }
651 0         0 my %skippers = map { $_, 1} @skippers;
  0         0  
652 0         0 $self->{Skipelements} = \%skippers;
653             }
654            
655 0   0     0 my @skippers_out = keys %{$self->{Skipelements}} || ();
656              
657 0 0       0 return wantarray ? @skippers_out : \@skippers_out;
658             }
659              
660              
661             ###
662             # Convenience helpers to make 'stream style' friendly
663             ###
664              
665             sub start_tag {
666 0     0 1 0 my $self = shift;
667 0         0 my $element_name = shift;
668 0         0 my %attrs = @_;
669 0         0 $self->start_element( $self->_start_details( $element_name, \%attrs ) );
670 0         0 push @{$self->{_Parents}}, $element_name;
  0         0  
671              
672             }
673              
674             sub end_tag {
675 0     0 1 0 my ($self, $tagname) = @_;
676 0         0 $self->end_element( $self->_end_details( $tagname ) );
677 0         0 pop (@{$self->{_Parents}});
  0         0  
678             }
679              
680             ####
681             # Internal Helpers
682             ###
683              
684             sub _keymapped_name {
685 35     35   52 my ($self, $name) = @_;
686 35         34 my $element_name;
687 35 100       110 if ( defined $self->{Keymap}->{$name} ) {
    50          
688 5         10 my $temp_name = $self->{Keymap}->{$name};
689              
690 5 50       16 if ( ref( $temp_name ) eq 'CODE' ) {
691 0         0 $element_name = &{$temp_name}( $name );
  0         0  
692             }
693             else {
694 5         15 $element_name = $temp_name;
695             }
696             }
697             elsif ( defined $self->{Keymap}->{'*'} ) {
698 0         0 my $temp_name = $self->{Keymap}->{'*'};
699            
700 0 0       0 if ( ref( $temp_name ) eq 'CODE' ) {
701 0         0 $element_name = &{$temp_name}( $name );
  0         0  
702             }
703             else {
704 0         0 $element_name = $temp_name;
705             }
706             }
707             else {
708 30         69 $element_name = $name;
709             }
710             }
711              
712             sub _start_details {
713 36     36   45 my $self = shift;
714 36         48 my ($element_name, $attrs) = @_;
715 36         43 my %real_attrs;
716 36         35 foreach my $attr (keys(%{$attrs})) {
  36         129  
717 2         3 my $uri;
718             my $prefix;
719 0         0 my $qname;
720 0         0 my $lname;
721              
722 2 50       6 if ( defined $self->{BindAttrs} ) {
723 0         0 ($uri, $prefix, $qname, $lname) = $self->_namespace_fixer( $attr );
724             }
725             else {
726 2         14 $lname = $self->_name_fixer( $attr );
727 2         3 $qname = $lname;
728             }
729              
730 2   50     20 my $key_uri = $uri || "";
731 2         17 $real_attrs{"\{$key_uri\}$lname"} = {
732             Name => $qname,
733             LocalName => $lname,
734             Prefix => $prefix,
735             NamespaceURI => $uri,
736             Value => $attrs->{$attr} };
737              
738             }
739              
740 36 100       47 if ( scalar( keys( %{$self->{Namespaces}} )) > scalar( keys( %{$self->{DeclaredNamespaces}} )) ) {
  36         62  
  36         123  
741 2         3 my @unseen_uris = grep { not defined $self->{DeclaredNamespaces}->{$_} } keys( %{$self->{Namespaces}} );
  8         20  
  2         10  
742 2         5 foreach my $uri ( @unseen_uris ) {
743 4         63 my $qname;
744             my $prefix;
745 0         0 my $lname;
746 0         0 my $key_uri;
747 0         0 my $ns_uri;
748              
749             # this, like the Java version of SAX2, explicitly follows production 5.2 of the
750             # W3C Namespaces rec.-- specifically:
751             # http://www.w3.org/TR/1999/REC-xml-names-19990114/#defaulting
752              
753 4 50       11 if ( $self->{Namespaces}->{$uri} eq '#default' ) {
754 0         0 $qname = 'xmlns';
755 0         0 $lname = 'xmlns';
756 0         0 $prefix = undef;
757 0         0 $key_uri = "";
758 0         0 $ns_uri = undef;
759             }
760             else {
761 4         14 $lname = $self->{Namespaces}->{$uri};
762 4         7 $prefix = 'xmlns';
763 4         7 $qname = $prefix . ':' . $lname;
764             #$key_uri = "";
765 4         5 $key_uri = $NS_XMLNS;
766 4         5 $ns_uri = $NS_XMLNS;
767              
768            
769             }
770 4         24 $real_attrs{"\{$key_uri\}$lname"} = {
771             Name => $qname,
772             LocalName => $lname,
773             Prefix => $prefix,
774             NamespaceURI => $ns_uri,
775             Value => $uri };
776              
777             # internal
778 4         8 $self->{DeclaredNamespaces}->{$uri} = $prefix;
779              
780             # fire events if needed.
781 4 50       12 if ( defined $prefix ) {
782 4         28 $self->start_prefix_mapping( { Prefix => $self->{Namespaces}->{$uri},
783             NamespaceURI => $uri
784             });
785             }
786             }
787             }
788              
789 36         149 my ($uri, $prefix, $qname, $lname) = $self->_namespace_fixer( $element_name );
790 36         184 my %element = (LocalName => $lname,
791             Name => $qname,
792             Prefix => $prefix,
793             NamespaceURI => $uri,
794             Attributes => \%real_attrs,
795             );
796              
797 36 100 100     88 if ( defined $uri and grep { $element_name eq $_ } @{$self->{Namespacemap}->{$uri}} ) {
  33         146  
  31         73  
798 5         15 push @{$self->{InScopeNamespaceStack}}, [$uri, $prefix];
  5         15  
799             }
800              
801            
802 36         199 return \%element;
803             }
804              
805             sub _end_details {
806 36     36   45 my $self = shift;
807 36         65 my ($element_name) = @_;
808 36         63 my ( $uri, $prefix, $qname, $lname ) = $self->_namespace_fixer( $element_name );
809 36         155 my %element = (LocalName => $lname,
810             Name => $qname,
811             Prefix => $prefix,
812             NamespaceURI => $uri,
813             );
814              
815 36 100 100     94 if ( defined $uri and grep { $element_name eq $_ } @{$self->{Namespacemap}->{$uri}} ) {
  33         137  
  31         68  
816 5         6 pop @{$self->{InScopeNamespaceStack}};
  5         10  
817             }
818              
819 36         176 return \%element;
820             }
821              
822             sub _namespace_fixer {
823 72     72   91 my ( $self, $node_name ) = @_;
824 72         69 my $prefix;
825             my $qname;
826 0         0 my $uri;
827 72         115 my $lname = $self->_name_fixer( $node_name );
828              
829 72         91 foreach my $ns ( keys( %{$self->{Namespacemap}} )) {
  72         183  
830 78 100       74 if ( grep { $node_name eq $_ } @{$self->{Namespacemap}->{"$ns"}} ) {
  86         329  
  78         314  
831 10         22 $uri = $ns;
832             }
833             }
834              
835 72 100       140 if ( defined( $uri ) ) {
836 10         24 $prefix = $self->{Namespaces}->{"$uri"};
837 10 50       20 if ( $prefix eq '#default' ) {
838 0         0 $prefix = undef;
839             }
840             else {
841 10         23 $qname = $prefix . ':' . $lname;
842             }
843 10   33     23 $qname ||= $lname;
844             }
845             else {
846 62 100       163 if ( defined $self->{InScopeNamespaceStack}->[-1] ) {
847 52         45 ($uri, $prefix) = @{$self->{InScopeNamespaceStack}->[-1]};
  52         146  
848 52 50       100 if ( $prefix ) {
849 52         102 $qname = $prefix . ':' . $lname;
850             }
851             }
852             }
853 72   66     168 $qname ||= $lname;
854 72         226 return ($uri, $prefix, $qname, $lname);
855             }
856              
857              
858             sub _name_fixer {
859 79     79   1183 my ($self, $name) = @_;
860             # UNICODE WARNING
861 79         195 $name =~ s|^[^a-zA-Z_:]{1}|_|g;
862 79         126 $name =~ tr|a-zA-Z0-9._:-|_|c;
863            
864 79         170 return $name;
865             }
866              
867             1;
868             __END__