in reply to
sub that finds ancestor elements
Code using XML::Simple rarely ends up being simple. It would be much easier if you used XML::LibXML...
#!/usr/bin/perl
use feature ":5.14";
use warnings FATAL => qw(all);
use strict;
use XML::LibXML 2;
my $x = XML::LibXML::->load_xml(string => <<'END');
<classes name="Panoply::BAR">
<public_methods>
<members name="BAR" const="no" kind="function" protection="public
+" static="no" virtualness="non_virtual" volatile="no">
<parameters declaration_name="pciReg" type="Register::Ptr" />
</members>
</public_methods>
<enums>
<members name="ObjectState" kind="enum" protection="public" stati
+c="no" virtualness="non_virtual">
<values name="NEW">
</values>
<values name="REFRESHED">
</values>
<values name="DIRTY">
</values>
</members>
</enums>
</classes>
END
sub _universal_find {
my $text = shift;
join '|',
"//$text", # Element name
"//*/\@$text", # Attribute name
"//*/text()[.='$text']", # Element contents
"//*/\@*[.='$text']", # Attribute value
}
my $coolNodeName = sub { ($_[0]->isa('XML::LibXML::Attr')?'@':'').$_[0
+]->nodeName };
for my $text (qw[ parameters pciReg DIRTY ])
{
say "Search for '$text'...";
for my $node ($x->findnodes( _universal_find($text) ))
{
say join ' => ',
$node->findnodes("ancestor::*")->map(sub { $coolNodeName->
+($_) }),
$coolNodeName->($node),
}
say "";
}
__END__
Search for 'parameters'...
classes => public_methods => members => parameters
Search for 'pciReg'...
classes => public_methods => members => parameters => @declaration_nam
+e
Search for 'DIRTY'...
classes => enums => members => values => @name
(Update: improved _universal_find to return attribute nodes instead of element nodes when attribute nodes are more appropriate; improved output.)
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'