File Coverage

lib/Class/XML/Parser.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Class::XML::Parser;
2              
3 11     11   9028 use strict;
  11         23  
  11         420  
4 11     11   62 use warnings;
  11         20  
  11         408  
5              
6 11     11   4726 use XML::Parser;
  0            
  0            
7             use Carp qw( croak );
8              
9             our $VERSION = '0.901';
10              
11             my $_parse_instance = undef;
12              
13             sub new {
14             my ( $class, %args ) = @_;
15              
16             my $pclass;
17             if ( $args{ validate } ) {
18             $pclass = 'XML::Checker::Parser';
19             eval "use $pclass";
20             } else {
21             $pclass = 'XML::Parser';
22             }
23              
24             my $parser = $pclass->new(
25             %args,
26             Style => "Stream",
27             Pkg => "Class::XML::Parser::Internal",
28             ) or croak "Couldn't create $pclass parser object";
29              
30             my $self = bless {
31             parser => $parser,
32             error => undef,
33             stack => Class::XML::Parser::Stack->new,
34             object_stack=> Class::XML::Parser::Stack->new,
35             root_class => $args{ root_class } || [ caller ]->[ 0 ],
36             prune => $args{ prune } || 0,
37             strip => $args{ strip } || 0,
38             map_uri => $args{ map_uri },
39             validate => $args{ validate } || 0,
40             }, $class;
41              
42             return $self
43             }
44              
45             sub last_error { shift->{ error } }
46              
47             sub parse {
48             my ( $self, $xml ) = @_;
49              
50             $_parse_instance = $self;
51              
52             my $parsed = undef;
53              
54             eval {
55             local $XML::Checker::FAIL = sub {
56             my ( $code, @params ) = @_;
57              
58             die XML::Checker::error_string( @_ ) if $code < 200;
59             };
60              
61             if ( $self->__validate and $self->__map_uri ) {
62             XML::Checker::Parser::map_uri( %{ $self->__map_uri } );
63             }
64              
65            
66             $parsed = $self->__parser->parse( $xml );
67             };
68             if ( $@ ) {
69             $self->__set_error( $@ );
70             return;
71             }
72              
73             undef $_parse_instance;
74              
75             return $self->{ object };
76             }
77              
78             sub __parser { $_[ 0 ]->{ parser } }
79             sub __validate { $_[ 0 ]->{ validate } }
80             sub __map_uri { $_[ 0 ]->{ map_uri } }
81             sub __stack { $_[ 0 ]->{ stack } }
82             sub __object_stack { $_[ 0 ]->{ object_stack } }
83             sub __root_class { $_[ 0 ]->{ root_class } }
84             sub __prune { $_[ 0 ]->{ prune } }
85             sub __strip { $_[ 0 ]->{ strip } }
86             sub __object { $_[ 0 ]->{ object } = $_[ 1 ] }
87             sub __parse_instance{ $_parse_instance }
88             sub __set_error { $_[ 0 ]->{ error } = $_[ 1 ] }
89              
90             package Class::XML::Parser::Internal;
91              
92             use constant ELEM => 0;
93             use constant OBJ => 1;
94              
95             my $instance = undef;
96              
97             sub StartDocument {
98             $instance = Class::XML::Parser->__parse_instance;
99             }
100              
101             sub EndDocument {
102             $instance = undef;
103             }
104              
105             sub StartTag {
106             my ( undef, $elem ) = @_;
107              
108             my %attributes = %_;
109              
110             my $stack = $instance->__stack;
111             my $obj_stack = $instance->__object_stack;
112              
113             my $item;
114             if ( $obj_stack->is_empty ) {
115             # set first element to be new instance of root class object
116             $stack->push( $elem );
117              
118             my $class = $instance->__root_class;
119              
120             my $ctor = $class->can( '__xml_parse_constructor' ) && $class->__xml_parse_constructor;
121             $ctor = 'new' if not defined $ctor;
122              
123             $item = $class->$ctor;
124             $obj_stack->push( [ $elem, $item ] );
125              
126             $instance->__object( $item );
127             } else {
128             $item = $obj_stack->peek->[ OBJ ];
129              
130             my $as_objects = $item->can( '__xml_parse_objects' ) && $item->__xml_parse_objects;
131              
132             my $alias = $elem;
133             if ( $item->can( '__xml_parse_aliases' ) ) {
134             my $aliases = $item->__xml_parse_aliases;
135              
136             $alias = $aliases->{ $elem }
137             if UNIVERSAL::isa( $aliases, 'HASH' ) and exists $aliases->{ $elem };
138             }
139              
140             my $class = $as_objects->{ $elem } if $as_objects;
141             if ( $class ) {
142             my $ctor = $class->can( '__xml_parse_constructor' ) && $class->__xml_parse_constructor;
143             $ctor = 'new' if not defined $ctor;
144              
145             my $new_item = $class->$ctor;
146              
147             $item->$alias( $new_item );
148             $item = $new_item;
149             $obj_stack->push( [ $elem, $item ] );
150             }
151             $stack->push( $elem );
152             }
153              
154             # set attributes
155             while ( my ( $k, $v ) = each %attributes ) {
156             $item->$k( $v );
157             }
158             }
159              
160             sub EndTag {
161             my ( undef, $elem ) = @_;
162              
163             $instance->__object_stack->pop
164             if $elem eq $instance->__object_stack->peek->[ ELEM ];
165              
166             $instance->__stack->pop;
167             }
168              
169             sub Text {
170             my $obj = $instance->__object_stack->peek->[ OBJ ];
171             my $elem = $instance->__stack->peek;
172              
173             if ( $instance->__strip ) {
174             s/^\s+//;
175             s/\s+$//;
176             }
177              
178             return
179             if /^\s*$/ and $instance->__prune;
180              
181             return
182             if $elem eq $instance->__object_stack->peek->[ ELEM ] and not $_;
183              
184             my $alias = $elem;
185             if ( $obj->can( '__xml_parse_aliases' ) ) {
186             my $aliases = $obj->__xml_parse_aliases;
187              
188             $alias = $aliases->{ $elem }
189             if UNIVERSAL::isa( $aliases, 'HASH' ) and exists $aliases->{ $elem };
190             }
191              
192             $obj->$alias( $_ );
193             }
194              
195             sub PI { }
196              
197             package Class::XML::Parser::Stack;
198              
199             sub new {
200             return bless [], shift;
201             }
202              
203             sub is_empty { return scalar @{ $_[ 0 ] } ? 0 : 1 }
204             sub push { push @{ $_[ 0 ] }, $_[ 1 ] }
205             sub pop { pop @{ $_[ 0 ] } }
206             sub peek { $_[ 0 ]->[-1] };
207              
208             1;
209              
210             __END__