| # |
| # CDDL HEADER START |
| # |
| # The contents of this file are subject to the terms of the |
| # Common Development and Distribution License (the "License"). |
| # You may not use this file except in compliance with the License. |
| # |
| # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| # or http://www.opensolaris.org/os/licensing. |
| # See the License for the specific language governing permissions |
| # and limitations under the License. |
| # |
| # When distributing Covered Code, include this CDDL HEADER in each |
| # file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| # If applicable, add the following below this CDDL HEADER, with the |
| # fields enclosed by brackets "[]" replaced with your own identifying |
| # information: Portions Copyright [yyyy] [name of copyright owner] |
| # |
| # CDDL HEADER END |
| # |
| # |
| # Copyright 2007 Sun Microsystems, Inc. All rights reserved. |
| # Use is subject to license terms. |
| # |
| # ident "%Z%%M% %I% %E% SMI" |
| # |
| |
| # <t> xmlHandlers -- package for generating a tree from an XML doc |
| |
| use XML::Parser; |
| |
| package xmlHandlers; |
| |
| $level = -1; |
| |
| %endCallback = (); |
| %startCallback = (); |
| |
| $currentObj = 0; |
| @objStack = (); |
| |
| 1; |
| |
| # <s> methods |
| |
| # pkg reference, object name (tag), optional fileName. |
| |
| |
| sub new { |
| my $pkg = shift; |
| my $parent = shift; # ref to parent object |
| my $class = shift; # for debug use |
| |
| my @kids = (); # list of child objects |
| |
| push (@objStack, $parent); |
| $currentObj = bless {'class' => $class, |
| 'kids' => \@kids, |
| # 'parent' => $parent, |
| 'attributes' => 0, |
| 'content' => ''}, $pkg; |
| |
| if (@_) { # if fileName passed, go! |
| die "parent for document creation must be null" |
| if ($parent); |
| executeXML (shift); |
| } |
| return $currentObj; |
| } |
| |
| # we'll call you when your object is started |
| # class method |
| |
| sub registerStartCallback { |
| my $objName = shift; # call me when you get <objName> |
| my $callback = shift; # \&foo($objRef, $source); |
| |
| if ($startCallback{$objName}) { |
| print STDERR "duplicate callback for $objName\n"; |
| return; |
| } |
| $startCallback{$objName} = $callback; |
| } |
| |
| |
| # we'll call you when your object is completed |
| # class method |
| |
| sub registerEndCallback { |
| my $objName = shift; # call me when you get </objName> |
| my $callback = shift; # \&foo($objRef); |
| |
| if ($endCallback{$objName}) { |
| print STDERR "duplicate callback for $objName\n"; |
| return; |
| } |
| $endCallback{$objName} = $callback; |
| } |
| |
| sub start { |
| } |
| sub end { |
| } |
| |
| sub char { |
| my ($obj, $class, $string) = @_; |
| |
| |
| } |
| |
| sub add { |
| my $parent = shift; |
| my $kid = shift; |
| |
| push (@{$parent->{'kids'}}, $kid); |
| # $kid->{'parent'} = $parent; |
| } |
| |
| # <s> internal functions |
| sub executeXML { |
| my $file = shift; |
| |
| # ErrorContext - 0 don't report errors |
| # - other = number of lines to display |
| # ParseparamEnt - 1 allow parsing of dtd |
| my $parser = XML::Parser->new(ErrorContext => 1, |
| ParseParamEnt => 1); |
| |
| $parser->setHandlers (Char => \&charHandler, |
| Start => \&startHandler, |
| Default => \&defaultHandler, |
| End => \&endHandler, |
| Proc => \&procHandler, |
| Comment => \&commentHandler, |
| ExternEnt => \&externalHandler); |
| |
| $parser->parsefile ($file); |
| } |
| |
| sub charHandler { |
| my ($xmlObj, $string) = @_; |
| |
| chomp $string; |
| $string =~ s/^\s+//; |
| $string =~ s/\s+$//; |
| unless ($string =~ /^\s*$/) { |
| # print "charHandler: $currentObj->{'class'} $string\n" if $main::debug; |
| $currentObj->{'content'} .= ' ' if ($currentObj->{'content'}); |
| $currentObj->{'content'} .= $string; |
| } |
| } |
| |
| # create new object and attach to tree |
| |
| sub startHandler { |
| my $xmlObj = shift; |
| my $tag = shift; |
| |
| my $obj; |
| my $parent = $currentObj; |
| |
| $obj = new xmlHandlers($currentObj, $tag); |
| |
| $parent->add ($obj); |
| |
| $obj->processAttributes ($tag, @_); |
| |
| my $functionRef; |
| if ($functionRef = $startCallback{$tag}) { |
| &$functionRef($obj, 'start'); |
| } |
| elsif ($main::debug) { |
| # print "no start callback for $tag\n"; |
| } |
| } |
| |
| sub endHandler { |
| my $xmlObj = shift; |
| my $element = shift; |
| |
| # print "end tag $element\n" if $main::debug; |
| |
| my $functionRef; |
| if ($functionRef = $endCallback{$element}) { |
| &$functionRef($currentObj, 'end'); |
| } |
| elsif ($main::debug) { |
| # print "no end callback for $element\n"; |
| } |
| # $currentObj = $currentObj->{'parent'}; |
| $currentObj = pop (@objStack); |
| } |
| |
| sub defaultHandler { |
| my ($obj, $string) = @_; |
| |
| unless (!$main::debug || ($string =~ /^\s*$/)) { |
| if ($string =~ /<\?xml/) { |
| $string =~ s/<\?\S+\s+(.*)/$1/; |
| my (%parameters) = |
| parseProcInstruction ($string); |
| print STDERR "Got call to default, guessed what to do: $string\n"; |
| } |
| else { |
| print STDERR "Got call to default, didn't know what to do: $string\n"; |
| } |
| } |
| } |
| |
| sub externalHandler { |
| my ($obj, $base, $sysid, $pubid) = @_; |
| |
| $base = '' if !$base; |
| $pubid = '' if !$pubid; |
| print "external: base $base\nexternal: sysid $sysid\nexternal: pubid $pubid\n"; |
| } |
| |
| sub commentHandler { |
| my ($obj, $element) = @_; |
| |
| return unless $main::debug; |
| |
| unless ($element =~ /^\s*$/) { |
| print "comment: $element\n"; |
| } |
| } |
| |
| sub procHandler { |
| my $xmlObj = shift; |
| my $target = shift; |
| my $data = shift; |
| |
| my (%parameters) = |
| parseProcInstruction ($data); |
| |
| $currentObj->processAttributes ($target, $data, @_); |
| } |
| #<s> misc subs |
| |
| sub parseProcInstruction { |
| my ($args) = @_; |
| |
| my (@outputArray) = (); |
| |
| while ($args =~ s/([^ =]+)=\"([^"]+)\"(.*)/$3/) { # " |
| push (@outputArray, $1); |
| push (@outputArray, $2); |
| } |
| return (@outputArray); |
| } |
| |
| sub processAttributes { |
| my $pkg = shift; |
| my ($element, %content) = @_; |
| |
| # print "processAttributes: element = $element\n" if $main::debug; |
| |
| my $hashCount = 0; |
| foreach $attributeName (keys %content) { |
| if ($attributeName =~ /^\s*$/) { |
| delete $content{$attributeName}; # remove null entries |
| next; |
| } |
| $hashCount++; |
| # print "attribute: $attributeName = $content{$attributeName}\n" |
| # if $main::debug; |
| } |
| if ($hashCount && $pkg->{'attributes'}) { |
| print STDERR "need to write attribute merge logic\n"; |
| } |
| else { |
| $pkg->{'attributes'} = \%content; |
| } |
| } |
| |
| sub getKid { |
| my $pkg = shift; |
| my $whichKid = shift; |
| |
| my @kids = $pkg->getKids(); |
| my $kid; |
| foreach $kid (@kids) { |
| my $class = $kid->getClass(); |
| return $kid if $class eq $whichKid; |
| } |
| return undef; |
| } |
| |
| sub getKids { |
| my $pkg = shift; |
| |
| return @{$pkg->{'kids'}}; |
| } |
| |
| sub getAttributes { |
| my $pkg = shift; |
| |
| my $ref = $pkg->{'attributes'}; |
| |
| return %$ref; |
| } |
| |
| sub getAttr { |
| my $pkg = shift; |
| my $attr = shift; |
| |
| my $ref = $pkg->{'attributes'}; |
| |
| return $$ref{$attr}; |
| } |
| |
| sub getClass { |
| my $pkg = shift; |
| |
| return $pkg->{'class'}; |
| } |
| |
| sub getContent { |
| my $pkg = shift; |
| |
| my $content = $pkg->{'content'}; |
| return $content ? $content : undef; |
| } |