1 # 2 # CDDL HEADER START 3 # 4 # The contents of this file are subject to the terms of the 5 # Common Development and Distribution License (the "License"). 6 # You may not use this file except in compliance with the License. 7 # 8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 # or http://www.opensolaris.org/os/licensing. 10 # See the License for the specific language governing permissions 11 # and limitations under the License. 12 # 13 # When distributing Covered Code, include this CDDL HEADER in each 14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 # If applicable, add the following below this CDDL HEADER, with the 16 # fields enclosed by brackets "[]" replaced with your own identifying 17 # information: Portions Copyright [yyyy] [name of copyright owner] 18 # 19 # CDDL HEADER END 20 # 21 # 22 # Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 # Use is subject to license terms. 24 # 25 # ident "%Z%%M% %I% %E% SMI" 26 # 27 28 # <t> xmlHandlers -- package for generating a tree from an XML doc 29 30 use XML::Parser; 31 32 package xmlHandlers; 33 34 $level = -1; 35 36 %endCallback = (); 37 %startCallback = (); 38 39 $currentObj = 0; 40 @objStack = (); 41 42 1; 43 44 # <s> methods 45 46 # pkg reference, object name (tag), optional fileName. 47 48 49 sub new { 50 my $pkg = shift; 51 my $parent = shift; # ref to parent object 52 my $class = shift; # for debug use 53 54 my @kids = (); # list of child objects 55 56 push (@objStack, $parent); 57 $currentObj = bless {'class' => $class, 58 'kids' => \@kids, 59 # 'parent' => $parent, 60 'attributes' => 0, 61 'content' => ''}, $pkg; 62 63 if (@_) { # if fileName passed, go! 64 die "parent for document creation must be null" 65 if ($parent); 66 executeXML (shift); 67 } 68 return $currentObj; 69 } 70 71 # we'll call you when your object is started 72 # class method 73 74 sub registerStartCallback { 75 my $objName = shift; # call me when you get <objName> 76 my $callback = shift; # \&foo($objRef, $source); 77 78 if ($startCallback{$objName}) { 79 print STDERR "duplicate callback for $objName\n"; 80 return; 81 } 82 $startCallback{$objName} = $callback; 83 } 84 85 86 # we'll call you when your object is completed 87 # class method 88 89 sub registerEndCallback { 90 my $objName = shift; # call me when you get </objName> 91 my $callback = shift; # \&foo($objRef); 92 93 if ($endCallback{$objName}) { 94 print STDERR "duplicate callback for $objName\n"; 95 return; 96 } 97 $endCallback{$objName} = $callback; 98 } 99 100 sub start { 101 } 102 sub end { 103 } 104 105 sub char { 106 my ($obj, $class, $string) = @_; 107 108 109 } 110 111 sub add { 112 my $parent = shift; 113 my $kid = shift; 114 115 push (@{$parent->{'kids'}}, $kid); 116 # $kid->{'parent'} = $parent; 117 } 118 119 # <s> internal functions 120 sub executeXML { 121 my $file = shift; 122 123 # ErrorContext - 0 don't report errors 124 # - other = number of lines to display 125 # ParseparamEnt - 1 allow parsing of dtd 126 my $parser = XML::Parser->new(ErrorContext => 1, 127 ParseParamEnt => 1); 128 129 $parser->setHandlers (Char => \&charHandler, 130 Start => \&startHandler, 131 Default => \&defaultHandler, 132 End => \&endHandler, 133 Proc => \&procHandler, 134 Comment => \&commentHandler, 135 ExternEnt => \&externalHandler); 136 137 $parser->parsefile ($file); 138 } 139 140 sub charHandler { 141 my ($xmlObj, $string) = @_; 142 143 chomp $string; 144 $string =~ s/^\s+//; 145 $string =~ s/\s+$//; 146 unless ($string =~ /^\s*$/) { 147 # print "charHandler: $currentObj->{'class'} $string\n" if $main::debug; 148 $currentObj->{'content'} .= ' ' if ($currentObj->{'content'}); 149 $currentObj->{'content'} .= $string; 150 } 151 } 152 153 # create new object and attach to tree 154 155 sub startHandler { 156 my $xmlObj = shift; 157 my $tag = shift; 158 159 my $obj; 160 my $parent = $currentObj; 161 162 $obj = new xmlHandlers($currentObj, $tag); 163 164 $parent->add ($obj); 165 166 $obj->processAttributes ($tag, @_); 167 168 my $functionRef; 169 if ($functionRef = $startCallback{$tag}) { 170 &$functionRef($obj, 'start'); 171 } 172 elsif ($main::debug) { 173 # print "no start callback for $tag\n"; 174 } 175 } 176 177 sub endHandler { 178 my $xmlObj = shift; 179 my $element = shift; 180 181 # print "end tag $element\n" if $main::debug; 182 183 my $functionRef; 184 if ($functionRef = $endCallback{$element}) { 185 &$functionRef($currentObj, 'end'); 186 } 187 elsif ($main::debug) { 188 # print "no end callback for $element\n"; 189 } 190 # $currentObj = $currentObj->{'parent'}; 191 $currentObj = pop (@objStack); 192 } 193 194 sub defaultHandler { 195 my ($obj, $string) = @_; 196 197 unless (!$main::debug || ($string =~ /^\s*$/)) { 198 if ($string =~ /<\?xml/) { 199 $string =~ s/<\?\S+\s+(.*)/$1/; 200 my (%parameters) = 201 parseProcInstruction ($string); 202 print STDERR "Got call to default, guessed what to do: $string\n"; 203 } 204 else { 205 print STDERR "Got call to default, didn't know what to do: $string\n"; 206 } 207 } 208 } 209 210 sub externalHandler { 211 my ($obj, $base, $sysid, $pubid) = @_; 212 213 $base = '' if !$base; 214 $pubid = '' if !$pubid; 215 print "external: base $base\nexternal: sysid $sysid\nexternal: pubid $pubid\n"; 216 } 217 218 sub commentHandler { 219 my ($obj, $element) = @_; 220 221 return unless $main::debug; 222 223 unless ($element =~ /^\s*$/) { 224 print "comment: $element\n"; 225 } 226 } 227 228 sub procHandler { 229 my $xmlObj = shift; 230 my $target = shift; 231 my $data = shift; 232 233 my (%parameters) = 234 parseProcInstruction ($data); 235 236 $currentObj->processAttributes ($target, $data, @_); 237 } 238 #<s> misc subs 239 240 sub parseProcInstruction { 241 my ($args) = @_; 242 243 my (@outputArray) = (); 244 245 while ($args =~ s/([^ =]+)=\"([^"]+)\"(.*)/$3/) { # " 246 push (@outputArray, $1); 247 push (@outputArray, $2); 248 } 249 return (@outputArray); 250 } 251 252 sub processAttributes { 253 my $pkg = shift; 254 my ($element, %content) = @_; 255 256 # print "processAttributes: element = $element\n" if $main::debug; 257 258 my $hashCount = 0; 259 foreach $attributeName (keys %content) { 260 if ($attributeName =~ /^\s*$/) { 261 delete $content{$attributeName}; # remove null entries 262 next; 263 } 264 $hashCount++; 265 # print "attribute: $attributeName = $content{$attributeName}\n" 266 # if $main::debug; 267 } 268 if ($hashCount && $pkg->{'attributes'}) { 269 print STDERR "need to write attribute merge logic\n"; 270 } 271 else { 272 $pkg->{'attributes'} = \%content; 273 } 274 } 275 276 sub getKid { 277 my $pkg = shift; 278 my $whichKid = shift; 279 280 my @kids = $pkg->getKids(); 281 my $kid; 282 foreach $kid (@kids) { 283 my $class = $kid->getClass(); 284 return $kid if $class eq $whichKid; 285 } 286 return undef; 287 } 288 289 sub getKids { 290 my $pkg = shift; 291 292 return @{$pkg->{'kids'}}; 293 } 294 295 sub getAttributes { 296 my $pkg = shift; 297 298 my $ref = $pkg->{'attributes'}; 299 300 return %$ref; 301 } 302 303 sub getAttr { 304 my $pkg = shift; 305 my $attr = shift; 306 307 my $ref = $pkg->{'attributes'}; 308 309 return $$ref{$attr}; 310 } 311 312 sub getClass { 313 my $pkg = shift; 314 315 return $pkg->{'class'}; 316 } 317 318 sub getContent { 319 my $pkg = shift; 320 321 my $content = $pkg->{'content'}; 322 return $content ? $content : undef; 323 } 324