use strict; use warnings; sub refClean { my @s = split /\n/, shift; my $m = 0; for my $line (@s) { next unless $line =~ /(.+)#__/; my $len = length($1); $m=$len>$m?$len:$m; } for my $line (@s) { next unless $line =~ /(.+)#__/; my $len = length($1); $line =~ s/#__/" " x ($m-$len)."#"/e; } return join "\n", @s; } sub refStructure { my $element = shift; my $level = shift; my $tab = shift; my $name = shift; my $s = $tab x $level; my $ctr = 0; my $r = ref($element); if( !$r ) { $s .= "'$element', #__ scalar: ".$name."\n"; } elsif( $r eq 'HASH' ) { $s .= "{ #__ ref to hash: ".$name."\n"; for my $key (keys %$element) { $s .= $tab x ($level+1)."'$key' => "; $s .= " #__ key of hash, string: +(keys %{".$name."})[".$ctr++."]\n"; $s .= refStructure( $element->{$key}, $level+2, $tab, $name."->{'".$key."'}" ); } $s .= $tab x $level."}\n"; } elsif( $r eq 'ARRAY' ) { $s .= "[ #__ ref to array: ".$name."\n"; map { $s .= refStructure( $_, $level+1, $tab, $name."->[".$ctr++."]" ) } @$element; $s .= $tab x $level."]\n"; } else { $s .= "$r #__ unknown type of reference\n"; } $s = refClean( $s )."\n" unless $level; return $s; } my $VAR1 = { 'IsLocked' => {}, 'ID' => '18827', 'TransactionID' => 'eb8xxx8-xxxb-4xx7-baed-xxx66c790c3', 'Name' => 'Production - xxxx', 'FarmRoleSet' => { 'Item' => [ { 'IsScalingEnabled' => '1', 'ServerSet' => { 'Item' => { 'Uptime' => '1452.4', 'ServerID' => 'xxxxc-487f-9281-0ebf39d2d4ea', 'Status' => 'Running', 'ExternalIP' => '54.193.71.108', 'Index' => '1', 'InternalIP' => '1.1.11.106', 'ScalarizrVersion' => '2.5.2', 'PlatformProperties' => { 'InstanceType' => 'm3.medium', 'InstanceID' => 'i-xxxx43', 'AMIID' => 'ami-xxxxxe97', 'AvailabilityZone' => 'us-west-1b' }, 'IsDbMaster' => '0' } }, 'ID' => '68608', 'RoleID' => '62343', 'Platform' => 'ec2', 'CloudLocation' => 'us-west-1', 'Name' => 'prod-app-xxx-v2', 'Category' => 'Application Servers', 'PlatformProperties' => { 'InstanceType' => 'm3.medium', 'AvailabilityZone' => 'x-scalr-diff' }, 'ScalingAlgorithmSet' => {}, 'ScalingProperties' => { 'MaxInstances' => '3', 'MinInstances' => '1' } }, { 'IsScalingEnabled' => '1', 'ServerSet' => { 'Item' => [ { 'Uptime' => '4438.55', 'ServerID' => 'xxxxx5-cfa7-4ea2-8013-34adxxxxxxx', 'Status' => 'Running', 'ExternalIP' => '999.999.1.187', 'Index' => '1', 'InternalIP' => '999.9.4.162', 'ScalarizrVersion' => '2.4.5', 'PlatformProperties' => { 'InstanceType' => 'm3.medium', 'InstanceID' => 'i-e6xxxx9', 'AMIID' => 'ami-94exxx', 'AvailabilityZone' => 'us-west-1b' }, 'IsDbMaster' => '1' }, { 'Uptime' => '4428.4', 'ServerID' => 'xxxxx-625f-4afc-b544-68fe0740dc0f', 'Status' => 'Running', 'ExternalIP' => '999.99.34.230', 'Index' => '2', 'InternalIP' => '999.99.3.165', 'ScalarizrVersion' => '2.4.5', 'PlatformProperties' => { 'InstanceType' => 'm3.medium', 'InstanceID' => 'i-xxx', 'AMIID' => 'ami-xxx', 'AvailabilityZone' => 'us-west-1b' }, 'IsDbMaster' => '0' } ] }, 'ID' => '68609', 'RoleID' => '61944', 'Platform' => 'ec2', 'DbMsrProperties' => { 'IsBackupRunning' => '1395658969', 'LastBundleTime' => '0', 'IsBundleRunning' => '0', 'LastBackupTime' => '1395475213' }, 'CloudLocation' => 'us-west-1', 'Name' => 'prod-xxx-platform-no-sync-db-mysql64-ubuntu1204', 'Category' => 'Databases', 'PlatformProperties' => { 'InstanceType' => 'm3.medium', 'AvailabilityZone' => 'us-west-1b' }, 'ScalingAlgorithmSet' => {}, 'ScalingProperties' => { 'MaxInstances' => '4', 'MinInstances' => '2' } } ] } }; print refStructure ($VAR1, 0, ' ', '$VAR1' );