hiptoss has asked for the wisdom of the Perl Monks concerning the following question:

I have looked over some previous entries about hashes of hashes and hashes of arrays, and I think I understand the concepts for the most part. I am failing miserably at trying to understand how to access data when it's nested among both types. This is a data structure that is returned from an external tool that I need to parse.
$VAR1 = { 'IsLocked' => {}, 'ID' => '18827', 'TransactionID' => 'eb8xxx8-xxxb-4xx7-baed-xxx66c790c3', 'Name' => 'Production - xxxx', 'FarmRoleSet' => { 'Item' => [ { 'IsScalingEnabled' => '1', 'ServerSet' => { 'Item' => { 'Uptim +e' => '1452.4', 'Serve +rID' => 'xxxxc-487f-9281-0ebf39d2d4ea', 'Statu +s' => 'Running', 'Exter +nalIP' => '54.193.71.108', 'Index +' => '1', 'Inter +nalIP' => '1.1.11.106', 'Scala +rizrVersion' => '2.5.2', 'Platf +ormProperties' => { + 'InstanceType' => 'm3.medium', + 'InstanceID' => 'i-xxxx43', + 'AMIID' => 'ami-xxxxxe97', + 'AvailabilityZone' => 'us-west-1b' + }, 'IsDbM +aster' => '0' } }, 'ID' => '68608', 'RoleID' => '62343', 'Platform' => 'ec2', 'CloudLocation' => 'us-west-1', 'Name' => 'prod-app-xxx-v2', 'Category' => 'Application Serv +ers', 'PlatformProperties' => { 'Instan +ceType' => 'm3.medium', 'Availa +bilityZone' => 'x-scalr-diff' }, 'ScalingAlgorithmSet' => {}, 'ScalingProperties' => { 'MaxInst +ances' => '3', 'MinInst +ances' => '1' } }, { 'IsScalingEnabled' => '1', 'ServerSet' => { 'Item' => [ { 'Upt +ime' => '4438.55', 'Ser +verID' => 'xxxxx5-cfa7-4ea2-8013-34adxxxxxxx', 'Sta +tus' => 'Running', 'Ext +ernalIP' => '999.999.1.187', 'Ind +ex' => '1', 'Int +ernalIP' => '999.9.4.162', 'Sca +larizrVersion' => '2.4.5', 'Pla +tformProperties' => { + 'InstanceType' => 'm3.medium', + 'InstanceID' => 'i-e6xxxx9', + 'AMIID' => 'ami-94exxx', + 'AvailabilityZone' => 'us-west-1b' + }, 'IsD +bMaster' => '1' }, { 'Upt +ime' => '4428.4', 'Ser +verID' => 'xxxxx-625f-4afc-b544-68fe0740dc0f', 'Sta +tus' => 'Running', 'Ext +ernalIP' => '999.99.34.230', 'Ind +ex' => '2', 'Int +ernalIP' => '999.99.3.165', 'Sca +larizrVersion' => '2.4.5', 'Pla +tformProperties' => { + 'InstanceType' => 'm3.medium', + 'InstanceID' => 'i-xxx', + 'AMIID' => 'ami-xxx', + 'AvailabilityZone' => 'us-west-1b' + }, 'IsD +bMaster' => '0' } ] }, 'ID' => '68609', 'RoleID' => '61944', 'Platform' => 'ec2', 'DbMsrProperties' => { 'IsBackupR +unning' => '1395658969', 'LastBundl +eTime' => '0', 'IsBundleR +unning' => '0', 'LastBacku +pTime' => '1395475213' }, 'CloudLocation' => 'us-west-1', 'Name' => 'prod-xxx-platform-no +-sync-db-mysql64-ubuntu1204', 'Category' => 'Databases', 'PlatformProperties' => { 'Instan +ceType' => 'm3.medium', 'Availa +bilityZone' => 'us-west-1b' }, 'ScalingAlgorithmSet' => {}, 'ScalingProperties' => { 'MaxInst +ances' => '4', 'MinInst +ances' => '2' } } ] } };
I'd love if there were a way to simply search for a particular key ID where another particular key matches a user defined regex. For example, I may only be interested in "ExternalIP" and "InstanceID" where the RoleID = $someNum. Short of that, I've tried several variations of what I think look to be the right way to address the structure and haven't yet figured it out. As an example:
print Dumper(@{$farmdetails->{FarmRoleSet}->{Item}}); #works as expect +ed print Dumper($farmdetails->{FarmRoleSet}->{Item}); #also works as expe +cted print Dumper($farmdetails->{FarmRoleSet}->{Item}->{ServerSet}); # fail +s - not a hashref print Dumper(@{$farmdetails->{FarmRoleSet}->{Item}->{ServerSet}}); # a +lso fails - not a hashref print Dumper(@{$farmdetails->{FarmRoleSet}->{Item}->[0]->{ServerSet}}) +; # also fails - not an arrayref print Dumper($farmdetails->{FarmRoleSet}->{Item}->[0]->{ServerSet}); # + works, displaying the first 'Item' array
When working with the last example, how can I iterate through the array items? Is there a better way to deal with heavily nested structures like this?

Replies are listed 'Best First'.
Re: deeply nested hashes of arrays of hashes of...
by tangent (Parson) on Mar 25, 2014 at 03:09 UTC
    It's a bit hard to decipher your data structure as you have used pre tags instead of code tags (see Markup in the Monastery) but you need to examine it closely and note where you have array references and where you have hash references. To answer your specific question this may help:
    my $items = $farmdetails->{FarmRoleSet}{Item}; for my $item (@$items) { next unless $item->{RoleID} == $some_number; my $ExternalIP = $item->{ServerSet}{Item}{ExternalIP}; my $InstanceID = $item->{ServerSet}{Item}{PlatformProperties}{Inst +anceID}; }
    When using Data::Dumper you don't need to dereference - print Dumper(@{ ... }) in your example - as Dumper will handle that for you:
    print Dumper($farmdetails->{FarmRoleSet}{Item}[0]); print Dumper($farmdetails->{FarmRoleSet}{Item}[0]{ServerSet}); # or better: my $items = $farmdetails->{FarmRoleSet}{Item}; for my $item (@$items) { print Dumper($item); print Dumper($item->{ServerSet}); }
Re: deeply nested hashes of arrays of hashes of...
by hdb (Monsignor) on Mar 26, 2014 at 19:23 UTC

    Here is a little script that tells you for each element what it is and how to address it: