Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

finding ancestor elements related to specific change

by jccunning (Acolyte)
on Oct 17, 2012 at 16:17 UTC ( #999574=perlquestion: print w/ replies, xml ) Need Help??
jccunning has asked for the wisdom of the Perl Monks concerning the following question:

I am using following subroutine in a api diff tool I am writing. Problem is that in the C++ api documentation there are class members or parameters with same name. The name is passed to routine as key for searching. When script compares to xml versions of the api and there is a change in one location, for example the type for the public method bits member has changed from uint32_t to uint64_t, then routine finds location for all members that are named "value". Would like to display only the search path containing the change. Initial thought is to pass entire line containing change as the search key. If this is possible, don't know how to implement. Any ideas.
#!/usr/bin/perl use warnings FATAL => qw(all); use strict; use Data::Dump qw(dump pp); use XML::Simple qw(:strict); use Data::Dumper; run(); sub run { my $xml = XMLin( <<'END', ForceArray => ['parameters'], KeyAttr => ['declaratio +n_name', 'name']); <classes name="Panoply::BAR"> <public_methods> <members name="BAR" const="no" kind="function" protection="publi +c" static="no" virtualness="non_virtual" volatile="no"> <parameters declaration_name="pciReg" type="Register::Ptr" /> </members> <members name="bits" const="no" kind="function" protection="publ +ic" static="no" type="void" virtualness="non_virtual" volatile="no"> <parameters declaration_name="value" type="uint64_t" /> </members> <members name="subBitVector" const="no" kind="function" protecti +on="public" static="no" type="void" virtualness="non_virtual" volatil +e="no"> <parameters declaration_name="value" type="const BitVector &am +p;" /> </members> </public_methods> <enums> <members name="ObjectState" kind="enum" protection="public" stat +ic="no" virtualness="non_virtual"> <values name="NEW"> </values> <values name="REFRESHED"> </values> <values name="DIRTY"> </values> </members> </enums> </classes> END my @list; my $sub = sub {push(@list, shift(@_) . ": " . join(" => ", @_))}; findPath($sub, $xml, "value"); print join("\n", @list), "\n"; } sub findPath { my ($sub, $xmlFrag, $match, @path) = @_; return unless $xmlFrag; if (ref($xmlFrag) =~ /HASH/) { for my $key (sort keys %$xmlFrag) { if ($key !~ /$match/) { findPath($sub, $xmlFrag->{$key}, $match, @path, $key); } else { $sub->($match, @path); } } } elsif (ref($xmlFrag) =~ /ARRAY/) { for my $fragIdx (0 .. $#$xmlFrag) { unless ($xmlFrag->[$fragIdx] =~ /$match/) { findPath($sub, $xmlFrag->[$fragIdx], $match, @path, $fragIdx + 1); } else { $sub->($match, @path); } } } return; }

Comment on finding ancestor elements related to specific change
Download Code
Re: finding ancestor elements related to specific change
by tobyink (Abbot) on Oct 17, 2012 at 23:09 UTC

    I'd strongly suggest dropping XML::Simple and using a DOM-based XML library. These tend to have useful methods called things like parentNode.

    use XML::LibXML 1.70; my $xml = XML::LibXML->load_xml(string => <<'END'); <classes name="Panoply::BAR"> <public_methods> <members name="BAR" const="no" kind="function" protection="publ +ic" static="no" virtualness="non_virtual" volatile="no"> <parameters declaration_name="pciReg" type="Register::Ptr" /> </members> <members name="bits" const="no" kind="function" protection="pub +lic" static="no" type="void" virtualness="non_virtual" volatile="no"> <parameters declaration_name="value" type="uint64_t" /> </members> <members name="subBitVector" const="no" kind="function" protect +ion="public" static="no" type="void" virtualness="non_virtual" volati +le="no"> <parameters declaration_name="value" type="const BitVector &a +mp;" /> </members> </public_methods> <enums> <members name="ObjectState" kind="enum" protection="public" sta +tic="no" virtualness="non_virtual"> <values name="NEW"> </values> <values name="REFRESHED"> </values> <values name="DIRTY"> </values> </members> </enums> </classes> END my @results = $xml->findnodes('//*[@declaration_name="value"]'); foreach my $result (@results) { print "Got result, with parent: ", $result->parentNode->getAttribu +te('name'), "\n"; }
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: finding ancestor elements related to specific change
by BrowserUk (Pope) on Oct 18, 2012 at 00:44 UTC

    #!/usr/bin/perl -slw use strict; use Data::Dump qw(dump pp); use XML::Simple qw(:strict); my $xml = XMLin( \*DATA, ForceArray => ['parameters','members','declar +ation_name'], KeyAttr => 0 ); #pp $xml; $_->{ kind } eq 'function' and grep{ $_->{ type } eq 'uint64_t' } @{ $_->{ parameters } } and print $_->{name} for @{ $xml->{public_methods}{members} }; __DATA__ <classes name="Panoply::BAR"> <public_methods> <members name="BAR" const="no" kind="function" protection="pub +lic" static="no" virtualness="non_virtual" volatile="no"> <parameters declaration_name="pciReg" type="Register::Ptr" + /> </members> <members name="bits" const="no" kind="function" protection="pu +blic" static="no" type="void" virtualness="non_virtual" volatile="no" +> <parameters declaration_name="value" type="uint64_t" /> </members> <members name="subBitVector" const="no" kind="function" protec +tion="public" static="no" type="void" virtualness="non_virtual" volat +ile="no"> <parameters declaration_name="value" type="const BitVector + &amp;" /> </members> </public_methods> <enums> <members name="ObjectState" kind="enum" protection="public" st +atic="no" virtualness="non_virtual"> <values name="NEW"> </values> <values name="REFRESHED"> </values> <values name="DIRTY"> </values> </members> </enums> </classes>

    Prints bits


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    RIP Neil Armstrong

Re: finding ancestor elements related to specific change
by Jenda (Abbot) on Oct 19, 2012 at 09:48 UTC

    Do you mean something like this?

    #!/usr/bin/perl -slw use strict; use Data::Dump qw(dump pp); use XML::Rules; my $parser = XML::Rules->new( rules => { parameters => sub { return '+has_uint64' => ($_[1]->{type} eq 'uint64_t'); }, members => sub { my ($tag,$attr,$context,$parents) = @_; return unless $context->[-2] eq 'classes'; my $class = $parents->[-2]{name}; (my $access = $context->[-1]) =~ s/_methods//; print "$access $class.$attr->{name} has $attr->{has_uint64 +} uint64 parameter(s)\n" if ($attr->{has_uint64}); return; }, '^enums' => 'skip', } ); $parser->parse(\*DATA); __DATA__ <classes name="Panoply::BAR"> <public_methods> ...

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://999574]
Approved by herveus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (11)
As of 2014-10-01 07:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (389 votes), past polls