File Coverage

blib/lib/XML/Smart/Parser.pm
Criterion Covered Total %
statement 111 118 94.0
branch 9 18 50.0
condition 14 15 93.3
subroutine 18 24 75.0
pod 0 11 0.0
total 152 186 81.7


line stmt bran cond sub pod time code
1             #############################################################################
2             ## Name: Parser.pm
3             ## Purpose: XML::Smart::Parser
4             ## Author: Paul Kulchenko (paulclinger@yahoo.com)
5             ## Modified by: Graciliano M. P.
6             ## Modified by: Harish Madabushi
7             ## Created: 10/05/2003
8             ## RCS-ID:
9             ## Copyright: 2000-2001 Paul Kulchenko
10             ## Licence: This program is free software; you can redistribute it and/or
11             ## modify it under the same terms as Perl itself
12             ##
13             ## This module is actualy XML::Parser::Lite (with some updates). It's here
14             ## just for convenience.
15             ##
16             ## See original code at CPAN for full source and POD.
17             ##
18             ## This module will be used when XML::Parser is not installed.
19             #############################################################################
20              
21             # ======================================================================
22             #
23             # Copyright (C) 2000-2001 Paul Kulchenko (paulclinger@yahoo.com)
24             # SOAP::Lite is free software; you can redistribute it
25             # and/or modify it under the same terms as Perl itself.
26             #
27             # $Id: Lite.pm,v 1.4 2001/10/15 21:25:05 paulk Exp $
28             #
29             # Changes: Graciliano M. P.
30             #
31             # ======================================================================
32              
33             package XML::Smart::Parser ;
34              
35 7     7   209 use 5.006 ;
  7         27  
  7         320  
36              
37 7     7   47 use strict ;
  7         14  
  7         256  
38 7     7   41 use warnings ;
  7         14  
  7         311  
39              
40 7     7   37 use vars qw($VERSION) ;
  7         12  
  7         413  
41              
42 7     7   41 use XML::Smart::Shared qw( _unset_sig_warn _reset_sig_warn ) ;
  7         29  
  7         13836  
43              
44             $VERSION = 1.31 ;
45              
46             my(@parsed , @stack, $level) ;
47              
48             &compile();
49              
50             sub new {
51              
52 163     163 0 516 _unset_sig_warn() ;
53 163 50       1281 my $class = ($_[0] =~ /^[\w:]+$/) ? shift(@_) : __PACKAGE__ ;
54 163         900 my $this = bless {} , $class ;
55              
56 163         387 my %args = @_ ;
57 163         535 _reset_sig_warn() ;
58              
59              
60 163         830 $this->setHandlers(%args) ;
61            
62 163         356 $this->{NOENTITY} = 1 ;
63              
64 163         554 return $this ;
65             }
66              
67             sub setHandlers {
68 326     326 0 903 _unset_sig_warn() ;
69 326         687 my $this = shift ;
70 326         992 my %args = @_;
71 326         840 _reset_sig_warn() ;
72            
73 326   100 0   2110 $this->{Init} = $args{Init} || sub{} ;
  0         0  
74 326   100 0   1689 $this->{Start} = $args{Start} || sub{} ;
  0         0  
75 326   100 0   1629 $this->{Char} = $args{Char} || sub{} ;
  0         0  
76 326   100 0   1576 $this->{End} = $args{End} || sub{} ;
  0         0  
77 326   100 0   1587 $this->{Final} = $args{Final} || sub{} ;
  0         0  
78            
79 326         958 return 1 ;
80             }
81              
82             sub regexp {
83 14   100 14 0 88 my $patch = shift || '' ;
84 14         24 my $package = __PACKAGE__ ;
85              
86 14         25 my $TextSE = "[^<]+";
87 14         23 my $UntilHyphen = "[^-]*-";
88 14         35 my $Until2Hyphens = "$UntilHyphen(?:[^-]$UntilHyphen)*-";
89 14         29 my $CommentCE = "$Until2Hyphens>?";
90 14         21 my $UntilRSBs = "[^\\]]*](?:[^\\]]+])*]+";
91 14         33 my $CDATA_CE = "$UntilRSBs(?:[^\\]>]$UntilRSBs)*>";
92 14         17 my $S = "[ \\n\\t\\r]+";
93 14         19 my $NameStrt = "[A-Za-z_:]|[^\\x00-\\x7F]";
94 14         19 my $NameChar = "[A-Za-z0-9_:.-]|[^\\x00-\\x7F]";
95 14         31 my $Name = "(?:$NameStrt)(?:$NameChar)*";
96 14         25 my $QuoteSE = "\"[^\"]*\"|'[^']*'";
97 14         36 my $DT_IdentSE = "$S$Name(?:$S(?:$Name|$QuoteSE))*";
98 14         32 my $MarkupDeclCE = "(?:[^\\]\"'><]+|$QuoteSE)*>";
99 14         18 my $S1 = "[\\n\\r\\t ]";
100 14         19 my $UntilQMs = "[^?]*\\?+";
101 14         189 my $PI_Tail = "\\?>|$S1$UntilQMs(?:[^>?]$UntilQMs)*>";
102 14         56 my $DT_ItemSE = "<(?:!(?:--$Until2Hyphens>|[^-]$MarkupDeclCE)|\\?$Name(?:$PI_Tail))|%$Name;|$S";
103 14         43 my $DocTypeCE = "$DT_IdentSE(?:$S)?(?:\\[(?:$DT_ItemSE)*](?:$S)?)?>?";
104 14         49 my $DeclCE = "--(?:$CommentCE)?|\\[CDATA\\[(?:($CDATA_CE)(?{${package}::char_CDATA(\$2)}))?|DOCTYPE(?:$DocTypeCE)?";
105 14         32 my $PI_CE = "$Name(?:$PI_Tail)?";
106              
107 14         39 my $EndTagCE = "($Name)(?{${package}::end(\$3)})(?:$S)?>";
108 14         20 my $AttValSE = "\"([^<\"]*)\"|'([^<']*)'";
109 14         60 my $ElemTagCE = "($Name)(?:$S($Name)(?:$S)?=(?:$S)?(?:$AttValSE)(?{[\@{\$^R||[]},\$5=>defined\$6?\$6:\$7]}))*(?:$S)?(/)?>(?{${package}::start(\$4,\@{\$^R||[]})})(?{\${8} and ${package}::end(\$4)})";
110 14         47 my $MarkupSPE = "<(?:!(?:$DeclCE)?|\\?(?:$PI_CE)?|/(?:$EndTagCE)?|(?:$ElemTagCE)?)";
111              
112 14         115 "(?:($TextSE)(?{${package}::char(\$1)}))$patch|$MarkupSPE";
113             }
114              
115             sub compile {
116             local $^W;
117            
118             foreach (regexp(), regexp('??')) {
119 7     7 0 47 eval qq{sub parse_re { use re "eval"; 1 while \$_[0] =~ m{$_}go }; 1} or die;
  7     170   14  
  7         4091  
  170         2289  
120             last if eval { parse_re('bar'); 1 }
121             };
122              
123             _unset_sig_warn() ;
124 0     0   0 *compile = sub {};
125             _reset_sig_warn() ;
126             }
127              
128             sub parse {
129 163     163 0 288 my $this = shift ;
130              
131              
132 163         321 @parsed = () ;
133              
134 163         424 init();
135 163         5536 parse_re($_[0]);
136 163         470 final();
137              
138 7     7   62 no strict qw(refs) ;
  7         14  
  7         4524  
139            
140 163         290 my $final = pop(@parsed) ; pop(@parsed) ;
  163         276  
141              
142 163         675 for (my $i = 0 ; $i <= $#parsed ; $i+=2) {
143 2919         4015 my $args = $parsed[$i+1] ;
144 2919 50       5557 &{$this->{$parsed[$i]}}($this , (ref($args) ? @{$args} : $args) ) ;
  2919         8951  
  2919         7722  
145             }
146              
147 163         1296 @parsed = () ;
148              
149 163         264 return &{$this->{Final}}($this, @{$final}) ;
  163         640  
  163         264  
150             }
151              
152             sub init {
153 163     163 0 498 @stack = (); $level = 0;
  163         339  
154 163         455 _unset_sig_warn() ;
155 163         477 push(@parsed , 'Init' , [@_]) ;
156 163         534 _reset_sig_warn() ;
157 163         397 return ;
158             }
159              
160             sub final {
161 163 50   163 0 527 die "not properly closed tag '$stack[-1]'\n" if @stack;
162 163 50       445 die "no element found\n" unless $level;
163 163         473 _unset_sig_warn() ;
164 163         439 push(@parsed , 'Final' , [@_]) ;
165 163         424 _reset_sig_warn() ;
166 163         424 return ;
167             }
168              
169             sub start {
170 789 50 66 789 0 3278 die "multiple roots, wrong element '$_[0]'\n" if $level++ && !@stack;
171 789         1909 _unset_sig_warn() ;
172 789         2066 push(@stack, $_[0]);
173 789         2709 push(@parsed , 'Start' , [@_]) ;
174 789         1913 _reset_sig_warn() ;
175 789         21000 return ;
176             }
177              
178             sub char {
179 1446 100   1446 0 40299 push(@parsed , 'Char' , [@_]) , return if @stack;
180              
181 247         971 for (my $i=0; $i < length $_[0]; $i++) {
182 422 0       2234 die "junk '$_[0]' @{[$level ? 'after' : 'before']} XML element\n"
  0 50       0  
183             if index("\n\r\t ", substr($_[0],$i,1)) < 0; # or should '< $[' be there
184             }
185 247         8543 return ;
186             }
187              
188             sub char_CDATA {
189 5     5 0 21 _unset_sig_warn() ;
190 5         22 &char( substr($_[0] , 0 , -3) ) ;
191 5         20 _reset_sig_warn() ;
192             }
193              
194             sub end {
195 789 50   789 0 2574 pop(@stack) eq $_[0] or die "mismatched tag '$_[0]'\n";
196 789         2443 push(@parsed , 'End' , [@_]) ;
197 789         24341 return ;
198             }
199              
200             # ======================================================================
201              
202             1;
203              
204