File Coverage

blib/lib/simpleXMLParse.pm
Criterion Covered Total %
statement 12 243 4.9
branch 0 54 0.0
condition n/a
subroutine 4 12 33.3
pod 0 2 0.0
total 16 311 5.1


line stmt bran cond sub pod time code
1             package simpleXMLParse;
2              
3             # Perl Module: simpleXMLParse
4             # Author: Daniel Edward Graham
5             # Copyright (c) Daniel Edward Graham 2008-2014
6             # Date: 12/7/2014
7             # License: LGPL 3.0
8             #
9              
10             require Exporter;
11 1     1   5983 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         1  
  1         107  
12             @ISA = qw(Exporter);
13              
14             # This allows declaration use simpleXMLParse ':all';
15             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
16             # will save memory.
17             %EXPORT_TAGS = ( 'all' => [ qw(
18            
19             ) ] );
20              
21             @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
22              
23             @EXPORT = qw(
24            
25             );
26              
27             $VERSION = '2.7';
28              
29 1     1   5 use Carp;
  1         1  
  1         54  
30 1     1   3 use strict;
  1         4  
  1         30  
31              
32 1     1   542 use open ':encoding(utf8)';
  1         1147  
  1         5  
33              
34             my @cdata;
35             my $cdataInd = 0;
36             my $MAXIND = 10000;
37              
38             sub new {
39 0     0 0   my $class = shift;
40 0 0         my %args = (@_ == 1) ? ((ref($_[0]) eq 'HASH') ? %{$_[0]}:(input => $_[0])):@_;
  0 0          
41 0           my $altstyle = 0;
42 0           my $fn;
43 0           $fn = $args{"input"};
44 0 0         $altstyle = 1 if ($args{"style"} eq '2');
45 0           my $self = {};
46 0           $self->{"xml"} = undef;
47 0           $self->{"data"} = undef;
48 0 0         open( INFILE, "$fn" ) or croak "Unable to process [$fn]\n";
49 0           $self->{"xml"} = join '', ;
50 0           close(INFILE);
51 0           $self->{"data"} = _ParseXML( $self->{"xml"} );
52 0           my $ret = bless $self;
53 0 0         if ($altstyle) {
54 0           $ret->_convertToStyle();
55             }
56 0           $cdataInd = $cdataInd % $MAXIND;
57 0           return $ret;
58             }
59              
60             sub parse {
61 0     0 0   my $self = shift;
62 0           return $self->{data};
63             }
64              
65             sub _convertToStyle {
66 0     0     my $self = shift;
67 0           my @recursearr = ($self->{"data"});
68 0           while (@recursearr) {
69 0           my $i = pop @recursearr;
70 0 0         if (ref($i) eq "HASH") {
71 0           foreach my $j (keys %$i) {
72 0 0         if ($j =~ /^(.*?)\_(.*?)\_([0-9]+)\_attr$/) {
73 0           my ($attrnm, $tagnm, $cnt) = ($1, $2, $3);
74 0           my $n = undef;
75 0 0         if (ref($i->{$tagnm}) eq "ARRAY") {
76 0           my $hold;
77 0 0         if (ref($i->{$tagnm}->[$cnt]) eq '') {
78 0           $hold = $i->{$tagnm}->[$cnt];
79 0           $i->{$tagnm}->[$cnt] = { };
80 0 0         if ($hold !~ /^\s*$/ ) {
81 0           $i->{$tagnm}->[$cnt]->{VALUE} = $hold;
82             }
83             }
84 0           while (defined($i->{$tagnm}->[$cnt]->{$attrnm.$n})) {
85 0           $n++;
86             }
87 0           $i->{$tagnm}->[$cnt]->{$attrnm.$n} = $i->{$j};
88             } else {
89 0 0         if (ref($i->{$tagnm}) eq "HASH") {
90 0           my $n = undef;
91 0           while (defined($i->{$tagnm}->{$attrnm.$n})) {
92 0           $n++;
93             }
94 0           $i->{$tagnm}->{$attrnm.$n} = $i->{$j};
95             } else {
96 0           my $hold;
97 0           $hold = $i->{$tagnm};
98 0           $i->{$tagnm} = { };
99 0 0         if ($hold !~ /^\s*$/) {
100 0           $i->{$tagnm}->{VALUE} = $hold;
101             }
102 0           $i->{$tagnm}->{$attrnm} = $i->{$j};
103             }
104             }
105 0           delete $i->{$j};
106             } else {
107 0           push @recursearr, $i->{$j};
108             }
109             }
110             } else {
111 0 0         if (ref($i) eq "ARRAY") {
112 0           foreach my $j (@$i) {
113 0           push @recursearr, $j;
114             }
115             }
116             }
117             }
118             }
119              
120             sub _cdatasub {
121 0     0     my $cdata = shift;
122 0           my $tmpind = $cdataInd++;
123 0           $cdata[$tmpind] = $cdata;
124 0           return "0x0CDATA0x0".($tmpind)."0x0";
125             }
126            
127             sub _cdatasubout {
128 0     0     my $ind = shift;
129 0           my $cdata = $cdata[$ind];
130 0           return $cdata;
131             }
132              
133             sub _unescp {
134 0     0     my $firsttag = shift;
135 0           $firsttag =~ s/\\\\/\\/gs;
136 0           $firsttag =~ s/\\\*/\*/gs;
137 0           $firsttag =~ s/\\\|/\|/gs;
138 0           $firsttag =~ s/\\\$/\$/gs;
139 0           $firsttag =~ s/\\\?/\?/gs;
140 0           $firsttag =~ s/\\\{/\{/gs;
141 0           $firsttag =~ s/\\\}/\}/gs;
142 0           $firsttag =~ s/\\\(/\(/gs;
143 0           $firsttag =~ s/\\\)/\)/gs;
144 0           $firsttag =~ s/\\\+/\+/gs;
145 0           $firsttag =~ s/\\\[/\[/gs;
146 0           $firsttag =~ s/\\\]/\]/gs;
147 0           $firsttag =~ s/\\\./\./gs;
148 0           $firsttag =~ s/\\\^/\^/gs;
149 0           $firsttag =~ s/\\\-/\-/gs;
150 0           return $firsttag;
151             }
152              
153             sub _entity {
154 0     0     my $text = shift;
155 0           $text =~ s/\<\;/\
156 0           $text =~ s/\>\;/\>/g;
157 0           $text =~ s/\&\;/\&/g;
158 0           $text =~ s/\&apos\;/\'/g;
159 0           $text =~ s/\"\;/\"/g;
160 0           return $text;
161             }
162              
163             sub _ParseXML {
164 0     0     my ($xml) = @_;
165             # $xml =~ s/\n//g;
166 0           $xml =~ s/\<\!\[CDATA\[(.*?)\]\]\>/&_cdatasub($1)/egs;
  0            
167 0           $xml =~ s/\<\!\-\-.*?\-\-\>//gs;
168 0           $xml =~ s/\<\?xml.*?\?\>//gs;
169 0           $xml =~ s/\<\?[^\>]*?\?\>//gs;
170 0           $xml =~ s/\<\!\-\-[^\>]*?\-\-\>//gs;
171 0           $xml =~ s/\<\!ELEMENT[^\>]*?\>//gs;
172 0           $xml =~ s/\<\!ENTITY[^\>]*?\>//gs;
173 0           $xml =~ s/\<\!DOCTYPE[^\>]*?\>//gs;
174 0           my $rethash = ();
175 0           my @retarr;
176 0           my $firsttag = $xml;
177 0           my ( $attr, $innerxml, $xmlfragment );
178 0           $firsttag =~ s/^[\s\n]*\<([^\s\>\n\/]*).*$/$1/gs;
179 0           $firsttag =~ s/\\/\\\\/gs;
180 0           $firsttag =~ s/\*/\\\*/gs;
181 0           $firsttag =~ s/\|/\\\|/gs;
182 0           $firsttag =~ s/\$/\\\$/gs;
183 0           $firsttag =~ s/\?/\\\?/gs;
184 0           $firsttag =~ s/\{/\\\{/gs;
185 0           $firsttag =~ s/\}/\\\}/gs;
186 0           $firsttag =~ s/\(/\\\(/gs;
187 0           $firsttag =~ s/\)/\\\)/gs;
188 0           $firsttag =~ s/\+/\\\+/gs;
189 0           $firsttag =~ s/\[/\\\[/gs;
190 0           $firsttag =~ s/\]/\\\]/gs;
191 0           $firsttag =~ s/\./\\\./gs;
192 0           $firsttag =~ s/\^/\\\^/gs;
193 0           $firsttag =~ s/\-/\\\-/gs;
194              
195 0 0         if ( $xml =~ /^[\s\n]*\<${firsttag}(\>|\s[^\>]*[^\/]\>)(.*?)\<\/${firsttag}\>(.*)$/s )
196             {
197 0           $attr = $1;
198 0           $innerxml = $2;
199 0           $xmlfragment = $3;
200 0           $attr =~ s/\>$//gs;
201             }
202             else {
203 0 0         if ( $xml =~ /^[\s\n]*\<${firsttag}(\/\>|\s[^\>]*\/\>)(.*)$/s ) {
204 0           $attr = $1;
205 0           $innerxml = "";
206 0           $xmlfragment = $2;
207             } else {
208 0 0         if (!ref($xml)) {
209 0           $xml = _entity($xml);
210 0           $xml =~ s/0x0CDATA0x0(\d+?)0x0/&_cdatasubout($1)/egs;
  0            
211             }
212 0           return $xml;
213             }
214             }
215 0           my $ixml = $innerxml;
216 0           while ($ixml =~ /^.*?\<${firsttag}(\>|\s[^\>]*[^\/]\>)(.*?)$/s) {
217 0           $ixml = $2;
218 0           print STDERR "***\n";
219 0           $innerxml .= "";
220 0 0         if ($xmlfragment =~ /^(.*?)\<\/${firsttag}\>(.*)$/s) {
221 0           my $ix = $1;
222 0           $innerxml .= $ix;
223 0           $ixml .= $ix;
224 0           $xmlfragment = $2;
225             } else {
226 0           die "Invalid XML innerxml: $innerxml\nixml: $ixml\nxmlfragment: $xmlfragment\n";
227             }
228             }
229 0           my $nextparse = _ParseXML($innerxml);
230 0           $rethash->{&_unescp($firsttag)} = $nextparse;
231 0           my @attrarr;
232 0           while ( $attr =~ s/^[\s\n]*([^\s\=\n]+)\s*\=\s*(\".*?\"|\'.*?\')(.*)$/$3/gs ) {
233 0           my ($name, $val) = ($1, $2);
234 0           $val =~ s/^\'(.*)\'$/$1/gs;
235 0           $val =~ s/^\"(.*)\"$/$1/gs;
236 0           push @attrarr, $name;
237 0           push @attrarr, _entity($val);
238             }
239 0           my $attrcnt = 0;
240 0           while ( my $val = shift(@attrarr) ) {
241 0           $rethash->{ "$val" . "_".&_unescp(${firsttag})."_" . $attrcnt . "_attr" } = shift(@attrarr);
242             }
243 0           my $retflag = 0;
244 0           my ( $xmlfragment1, $xmlfragment2 );
245 0           my %attrhash;
246 0           $attrcnt++;
247 0           while (1) {
248 0 0         if ( $xmlfragment =~
249             /^(.*?)\<${firsttag}(\>|\s[^\>]*[^\/]\>)(.*?)\<\/${firsttag}\>(.*)$/s )
250             {
251 0 0         if ( !$retflag ) {
252 0           push @retarr, $nextparse;
253             }
254 0           $retflag = 1;
255 0           $xmlfragment1 = $1;
256 0           $attr = $2;
257 0           $innerxml = $3;
258 0           $xmlfragment2 = $4;
259             } else {
260 0 0         if ( $xmlfragment =~ /^(.*?)\<${firsttag}(\/\>|\s[^\>]*\/\>)(.*)$/s ) {
261 0 0         if ( !$retflag ) {
262 0           push @retarr, $nextparse;
263             }
264 0           $retflag = 1;
265 0           $xmlfragment1 = $1;
266 0           $attr = $2;
267 0           $innerxml = "";
268 0           $xmlfragment2 = $3;
269             } else {
270 0           last;
271             }
272             }
273 0           $attr =~ s/\>$//gs;
274 0           my %opening = ( );
275 0           my %closing = ( );
276 0           my $frag = $xmlfragment1;
277 0           while ($frag =~ /^(.*?)\<([^\s\n\/]+)[^\/]*?\>(.*)$/s) {
278 0           my $tg = $2;
279 0           $frag = $3;
280 0           $opening{$tg}++;
281             }
282 0           my $frag = $xmlfragment1;
283 0           while ($frag =~ /^(.*?)\<\/([^\s\n]+)\>(.*)$/s) {
284 0           my $tg = $2;
285 0           $frag = $3;
286 0           $closing{$tg}++;
287             }
288 0           my $flag = 0;
289 0           foreach my $k (keys %opening) {
290 0 0         if ($opening{$k} > $closing{$k}) {
291 0           $xmlfragment = $xmlfragment1 . "<${firsttag}0x0 ${attr}>${innerxml}". $xmlfragment2;
292 0           $flag = 1;
293 0           last;
294             }
295             }
296 0 0         next if ($flag);
297 0           my $ixml = $innerxml;
298 0           while ($ixml =~ /.*?\<${firsttag}(\>|\s[^\>]*[^\/]\>)(.*?)$/s) {
299 0           $ixml = $2;
300 0           $innerxml .= "";
301 0 0         if ($xmlfragment2 =~ /(.*?)\<\/${firsttag}\>(.*)$/s) {
302 0           my $ix = $1;
303 0           $innerxml .= $ix;
304 0           $ixml .= $ix;
305 0           $xmlfragment2 = $2;
306             } else {
307 0           die "Invalid XML";
308             }
309             }
310 0           $xmlfragment = $xmlfragment1 . $xmlfragment2;
311 0           while ( $attr =~ s/^[\s\n]*([^\s\=\n]+)\s*\=\s*(\".*?\"|\'.*?\')(.*)$/$3/gs ) {
312 0           my ($name, $val) = ($1, $2);
313 0           $val =~ s/^\'(.*)\'$/$1/gs;
314 0           $val =~ s/^\"(.*)\"$/$1/gs;
315 0           push @attrarr, $name;
316 0           push @attrarr, _entity($val);
317             }
318 0           while ( my $val = shift(@attrarr) ) {
319 0           $rethash->{ "$val" . "_".&_unescp(${firsttag})."_" . $attrcnt . "_attr" } = shift(@attrarr);
320             }
321 0           $attrcnt++;
322 0           $nextparse = _ParseXML($innerxml);
323 0           push @retarr, $nextparse;
324             }
325 0 0         if (@retarr) {
326 0           $rethash->{_unescp($firsttag)} = \@retarr;
327             }
328 0           $xmlfragment =~ s/${firsttag}0x0/${firsttag}/gs;
329 0           my $remainderparse = _ParseXML($xmlfragment);
330 0           my $attrcnt;
331             my $attrfrag;
332 0 0         if ( ref($remainderparse) eq "HASH" ) {
333 0           foreach ( keys %{$remainderparse} ) {
  0            
334 0           $rethash->{&_unescp($_)} = $remainderparse->{&_unescp($_)};
335             }
336             }
337 0 0         if ( keys %{$rethash} ) {
  0            
338 0           return $rethash;
339             }
340             else {
341 0           return undef;
342             }
343             }
344              
345             1;
346             __END__