File Coverage

blib/lib/XML/Generator/PerlData.pm
Criterion Covered Total %
statement 356 535 66.5
branch 129 238 54.2
condition 40 61 65.5
subroutine 32 42 76.1
pod 26 32 81.2
total 583 908 64.2


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