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