File Coverage

blib/lib/simpleXMLParse.pm
Criterion Covered Total %
statement 12 216 5.5
branch 0 54 0.0
condition n/a
subroutine 4 10 40.0
pod 0 4 0.0
total 16 284 5.6


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: 3/25/2014
7             # License: LGPL 3.0
8             #
9              
10             require Exporter;
11 1     1   10971 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         4  
  1         190  
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.6';
28              
29 1     1   7 use Carp;
  1         8  
  1         218  
30 1     1   6 use strict;
  1         6  
  1         51  
31              
32 1     1   1681 use open ':encoding(utf8)';
  1         6449  
  1         8  
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         if ( @_ != 1 ) {
41 0           croak "Invalid usage (new)\n";
42             }
43 0           my $inputfile = shift;
44 0           my $altstyle = 0;
45 0           my $fn;
46 0 0         if ( ref($inputfile) eq "HASH" ) {
47 0           $fn = $inputfile->{"input"};
48 0 0         $altstyle = 1 if ($inputfile->{"style"} eq '2');
49             }
50 0           my $self = {};
51 0           $self->{"xml"} = undef;
52 0           $self->{"data"} = undef;
53 0 0         open( INFILE, "$fn" ) or croak "Unable to process [$fn]\n";
54 0           $self->{"xml"} = join '', ;
55 0           close(INFILE);
56 0           $self->{"xml"} =~ s/\<\?[^\>]*?\?\>//g;
57 0           $self->{"xml"} =~ s/\<\!\-\-[^\>]*?\-\-\>//g;
58 0           $self->{"data"} = _ParseXML( $self->{"xml"} );
59 0           my $ret = bless $self;
60 0 0         if ($altstyle) {
61 0           warn "alt style";
62 0           $ret->_convertToStyle();
63             }
64 0           $cdataInd = $cdataInd % $MAXIND;
65 0           return $ret;
66             }
67              
68             sub parse {
69 0     0 0   my $self = shift;
70 0           return $self->{data};
71             }
72              
73             sub _convertToStyle {
74 0     0     my $self = shift;
75 0           my @recursearr = ($self->{"data"});
76 0           while (@recursearr) {
77 0           my $i = pop @recursearr;
78 0 0         if (ref($i) eq "HASH") {
79 0           foreach my $j (keys %$i) {
80 0 0         if ($j =~ /^(.*?)\_(.*?)\_([0-9]+)\_attr$/) {
81 0           my ($attrnm, $tagnm, $cnt) = ($1, $2, $3);
82 0           my $n = undef;
83 0 0         if (ref($i->{$tagnm}) eq "ARRAY") {
84 0           my $hold;
85 0 0         if (ref($i->{$tagnm}->[$cnt]) eq '') {
86 0           $hold = $i->{$tagnm}->[$cnt];
87 0           $i->{$tagnm}->[$cnt] = { };
88 0 0         if ($hold !~ /^\s*$/ ) {
89 0           $i->{$tagnm}->[$cnt]->{VALUE} = $hold;
90             }
91             }
92 0           while (defined($i->{$tagnm}->[$cnt]->{$attrnm.$n})) {
93 0           $n++;
94             }
95 0           $i->{$tagnm}->[$cnt]->{$attrnm.$n} = $i->{$j};
96             } else {
97 0 0         if (ref($i->{$tagnm}) eq "HASH") {
98 0           my $n = undef;
99 0           while (defined($i->{$tagnm}->{$attrnm.$n})) {
100 0           $n++;
101             }
102 0           $i->{$tagnm}->{$attrnm.$n} = $i->{$j};
103             } else {
104 0           my $hold;
105 0           $hold = $i->{$tagnm};
106 0           $i->{$tagnm} = { };
107 0 0         if ($hold !~ /^\s*$/) {
108 0           $i->{$tagnm}->{VALUE} = $hold;
109             }
110 0           $i->{$tagnm}->{$attrnm} = $i->{$j};
111             }
112             }
113 0           delete $i->{$j};
114             } else {
115 0           push @recursearr, $i->{$j};
116             }
117             }
118             } else {
119 0 0         if (ref($i) eq "ARRAY") {
120 0           foreach my $j (@$i) {
121 0           push @recursearr, $j;
122             }
123             }
124             }
125             }
126             }
127              
128             sub cdatasub {
129 0     0 0   my $cdata = shift;
130 0           my $tmpind = $cdataInd++;
131 0           $cdata[$tmpind] = $cdata;
132 0           return "0x0CDATA0x0".($tmpind)."0x0";
133             }
134            
135             sub cdatasubout {
136 0     0 0   my $ind = shift;
137 0           my $cdata = $cdata[$ind];
138 0           return $cdata;
139             }
140              
141             sub _ParseXML {
142 0     0     my ($xml) = @_;
143 0           $xml =~ s/\n//g;
144 0           $xml =~ s/\<\!\-\-.*?\-\-\>//g;
145 0           $xml =~ s/\<\?xml.*?\?\>//g;
146 0           $xml =~ s/\<\!\[CDATA\[(.*?)\]\]\>/&cdatasub($1)/eg;
  0            
147 0           my $rethash = ();
148 0           my @retarr;
149 0           my $firsttag = $xml;
150 0           my ( $attr, $innerxml, $xmlfragment );
151 0           $firsttag =~ s/^[\s\n]*\<([^\s\>\n\/]*).*$/$1/g;
152 0           $firsttag =~ s/\\/\\\\/g;
153 0           $firsttag =~ s/\*/\\\*/g;
154 0           $firsttag =~ s/\{/\\\{/g;
155 0           $firsttag =~ s/\}/\\\}/g;
156 0           $firsttag =~ s/\(/\\\(/g;
157 0           $firsttag =~ s/\)/\\\)/g;
158 0           $firsttag =~ s/\=/\\\=/g;
159 0           $firsttag =~ s/\+/\\\+/g;
160 0           $firsttag =~ s/\[/\\\[/g;
161 0           $firsttag =~ s/\]/\\\]/g;
162 0           $firsttag =~ s/\./\\\./g;
163 0           $firsttag =~ s/\-/\\\-/g;
164              
165 0 0         if ( $xml =~ /^[\s\n]*\<${firsttag}(\>|\s[^\>]*[^\/]\>)(.*?)\<\/${firsttag}\>(.*)$/ )
166             {
167 0           $attr = $1;
168 0           $innerxml = $2;
169 0           $xmlfragment = $3;
170 0           $attr =~ s/\>$//g;
171             }
172             else {
173 0 0         if ( $xml =~ /^[\s\n]*\<${firsttag}(\/\>|\s[^\>]*\/\>)(.*)$/ ) {
174 0           $attr = $1;
175 0           $innerxml = "";
176 0           $xmlfragment = $2;
177             } else {
178 0 0         if (!ref($xml)) {
179 0           $xml =~ s/0x0CDATA0x0(\d+?)0x0/&cdatasubout($1)/eg;
  0            
180             }
181 0           return $xml;
182             }
183             }
184 0           my $ixml = $innerxml;
185 0           while ($ixml =~ /^.*?\<${firsttag}(\>|\s[^\>]*[^\/]\>)(.*?)$/) {
186 0           $ixml = $2;
187 0           print STDERR "***\n";
188 0           $innerxml .= "";
189 0 0         if ($xmlfragment =~ /^(.*?)\<\/${firsttag}\>(.*)$/) {
190 0           my $ix = $1;
191 0           $innerxml .= $ix;
192 0           $ixml .= $ix;
193 0           $xmlfragment = $2;
194             } else {
195 0           die "Invalid XML innerxml: $innerxml\nixml: $ixml\nxmlfragment: $xmlfragment\n";
196             }
197             }
198 0           my $nextparse = _ParseXML($innerxml);
199 0           $rethash->{"$firsttag"} = $nextparse;
200 0           my @attrarr;
201 0           while ( $attr =~ s/^[\s\n]*([^\s\=\n]+)\s*\=\s*(\".*?\"|\'.*?\')(.*)$/$3/g ) {
202 0           my ($name, $val) = ($1, $2);
203 0           $val =~ s/^\'(.*)\'$/$1/g;
204 0           $val =~ s/^\"(.*)\"$/$1/g;
205 0           push @attrarr, $name;
206 0           push @attrarr, $val;
207             }
208 0           my $attrcnt = 0;
209 0           while ( my $val = shift(@attrarr) ) {
210 0           $rethash->{ "$val" . "_${firsttag}_" . $attrcnt . "_attr" } = shift(@attrarr);
211             }
212 0           my $retflag = 0;
213 0           my ( $xmlfragment1, $xmlfragment2 );
214 0           my %attrhash;
215 0           $attrcnt++;
216 0           while (1) {
217 0 0         if ( $xmlfragment =~
218             /^(.*?)\<${firsttag}(\>|\s[^\>]*[^\/]\>)(.*?)\<\/${firsttag}\>(.*)$/ )
219             {
220 0 0         if ( !$retflag ) {
221 0           push @retarr, $nextparse;
222             }
223 0           $retflag = 1;
224 0           $xmlfragment1 = $1;
225 0           $attr = $2;
226 0           $innerxml = $3;
227 0           $xmlfragment2 = $4;
228             } else {
229 0 0         if ( $xmlfragment =~ /^(.*?)\<${firsttag}(\/\>|\s[^\>]*\/\>)(.*)$/ ) {
230 0 0         if ( !$retflag ) {
231 0           push @retarr, $nextparse;
232             }
233 0           $retflag = 1;
234 0           $xmlfragment1 = $1;
235 0           $attr = $2;
236 0           $innerxml = "";
237 0           $xmlfragment2 = $3;
238             } else {
239 0           last;
240             }
241             }
242 0           $attr =~ s/\>$//g;
243 0           my %opening = ( );
244 0           my %closing = ( );
245 0           my $frag = $xmlfragment1;
246 0           while ($frag =~ /^(.*?)\<([^\s\n\/]+)[^\/]*?\>(.*)$/) {
247 0           my $tg = $2;
248 0           $frag = $3;
249 0           $opening{$tg}++;
250             }
251 0           my $frag = $xmlfragment1;
252 0           while ($frag =~ /^(.*?)\<\/([^\s\n]+)\>(.*)$/) {
253 0           my $tg = $2;
254 0           $frag = $3;
255 0           $closing{$tg}++;
256             }
257 0           my $flag = 0;
258 0           foreach my $k (keys %opening) {
259 0 0         if ($opening{$k} > $closing{$k}) {
260 0           $xmlfragment = $xmlfragment1 . "<${firsttag}0x0 ${attr}>${innerxml}". $xmlfragment2;
261 0           $flag = 1;
262 0           last;
263             }
264             }
265 0 0         next if ($flag);
266             # $xmlfragment = $xmlfragment1 . $xmlfragment2;
267 0           my $ixml = $innerxml;
268 0           while ($ixml =~ /.*?\<${firsttag}(\>|\s[^\>]*[^\/]\>)(.*?)$/) {
269 0           $ixml = $2;
270 0           $innerxml .= "";
271 0 0         if ($xmlfragment2 =~ /(.*?)\<\/${firsttag}\>(.*)$/) {
272 0           my $ix = $1;
273 0           $innerxml .= $ix;
274 0           $ixml .= $ix;
275 0           $xmlfragment2 = $2;
276             } else {
277 0           die "Invalid XML";
278             }
279             }
280 0           $xmlfragment = $xmlfragment1 . $xmlfragment2;
281 0           while ( $attr =~ s/^[\s\n]*([^\s\=\n]+)\s*\=\s*(\".*?\"|\'.*?\')(.*)$/$3/g ) {
282 0           my ($name, $val) = ($1, $2);
283 0           $val =~ s/^\'(.*)\'$/$1/g;
284 0           $val =~ s/^\"(.*)\"$/$1/g;
285 0           push @attrarr, $name;
286 0           push @attrarr, $val;
287             }
288 0           while ( my $val = shift(@attrarr) ) {
289             # if (defined($rethash->{"$val" . "_$firsttag" . "_attr" })) {
290             # $rethash->{ "$val" . "_${firsttag}_" . ++$attrhash{"$val" . "_$firsttag" . "_attr"} . "_attr" } = shift(@attrarr);
291 0           $rethash->{ "$val" . "_${firsttag}_" . $attrcnt . "_attr" } = shift(@attrarr);
292             # } else {
293             # $rethash->{ "$val" . "_$firsttag" . "_attr" } = shift(@attrarr);
294             # }
295             }
296 0           $attrcnt++;
297 0           $nextparse = _ParseXML($innerxml);
298 0           push @retarr, $nextparse;
299             }
300 0 0         if (@retarr) {
301 0           $rethash->{"$firsttag"} = \@retarr;
302             }
303 0           $xmlfragment =~ s/${firsttag}0x0/${firsttag}/g;
304 0           my $remainderparse = _ParseXML($xmlfragment);
305 0           my $attrcnt;
306             my $attrfrag;
307 0 0         if ( ref($remainderparse) eq "HASH" ) {
308 0           foreach ( keys %{$remainderparse} ) {
  0            
309 0           $rethash->{"$_"} = $remainderparse->{"$_"};
310             }
311             }
312 0 0         if ( keys %{$rethash} ) {
  0            
313 0           return $rethash;
314             }
315             else {
316 0           return undef;
317             }
318             }
319              
320             1;
321             __END__