http://www.perlmonks.org?node_id=1031129


in reply to Traversing a complex data structure searching for certain keys and printing their values

To get the output you requested, I had to make several assumptions:
  1. The %filer_device and %filer_volume type of subhashes are of depth 1 (i.e. @west and @ridge are not structures).
  2. %defaults are special and their name must be hardcoded.

#!/usr/bin/perl use warnings; use strict; use v5.14; # Hashrefs for keys and values. use JSON; use Data::Dumper; sub recurse_hash { my ($hash, $found, @findkeys) = @_; for my $key (sort { # Defaults go first. local $a = q() if '%default' eq $a; local $b = q() if '%default' eq $b; $a cmp $b; } keys %{$hash}) { my $value = $hash->{$key}; if ('HASH' eq ref $value) { $found = {%$found, %{ recurse_hash($value, $found, @findke +ys) }}; } for my $find (@findkeys) { if ($key eq $find) { if ('HASH' eq ref $value) { $found->{$key} = [ map $value->{$_}, sort keys $va +lue ]; } else { $found->{$key} = $value; } } } } if (@findkeys == keys $found) { my $count; $count = @{ (grep 'ARRAY' eq ref $_, values $found)[0] // [] } +; $count ||= 1; for my $i (0 .. $count - 1) { print join(':', map { 'ARRAY' eq ref $_ ? $_->[$i] : $_ } @{$found}{@findkeys}), "\n"; } print "\n"; $found = {}; } return $found; } my @keylist = qw(%export_name %filer_device %filer_volume %mount_acl %mount_group %mount_user %mount_opts); my $string = do { local $/; <DATA> }; my $struct = decode_json($string); recurse_hash($struct, {}, @keylist); __DATA__ { "%name": "Global Central Configuration file", "%description": "A representation of nfs mount points for dev mach +ines", "%schema": "schema.conf", "@dev": { "home_nfs": { "%default": { "%mount_opts": "nfsvers=3,timeo=600,retrans=2", "%mount_user": "root", "%mount_group": "root", "%mount_acl": "0755" }, "%comment": "----Home NFS Directories----", "home-lnk-mpt": { "%export_name": "/links", "%filer_device": { "@west": "nydevnfs_links", "@ridge": "rnap7750-s" }, "%filer_volume": { "@west": "/vol/links", "@ridge": "/vol/links_c" } }, "home7_mpt": { "%export_name": "/home7", "%filer_device": { "@west": "nydevnfs_home7", "@ridge": "rnap7751-s" }, "%filer_volume": { "@west": "/vol/home7", "@ridge": "/vol/home7_c" } }, "home8_mpt": { "%export_name": "/home8", "%filer_device": { "@west": "nydevnfs_home2", "@ridge": "rnap2114-s" }, "%filer_volume": { "@west": "/vol/home2", "@ridge": "/vol/home2_c" } } } } }
لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
  • Comment on Re: Traversing a complex data structure searching for certain keys and printing their values
  • Select or Download Code

Replies are listed 'Best First'.
Re^2: Traversing a complex data structure searching for certain keys and printing their values
by newperluser2013 (Novice) on Apr 29, 2013 at 01:07 UTC

    Thanks for your help. This looks really good. Unfortunately I only have perl 5.12 so this fails with these errors

    Type of arg 1 to keys must be hash or array (not private variable) at +./test.pl line 25, near "$value ]" Type of arg 1 to keys must be hash or array (not private variable) at +./test.pl line 32, near "$found) " Type of arg 1 to values must be hash or array (not private variable) a +t ./test.pl line 34, near "$found)"

    Also as regards %filer_device and %filer_volume sometimes in this data structure these are not hashes, sometimes both are, and sometimes one is and the other isn't I am really not too sure how to go about dealing with that :-( Also regarding the %defaults section I am not allowed to hardcode that. In the small sample of this data structure I have shown this is tied in to the tag "@dev". So any mountpoint defined under here gets those permissions. In the rest of the data structure I have other tags like @build and @software and under each one of these they have their own set of multiple mount point definitions and their own set of default permissions that need to be set. I ultimately need to print the strings out in the following format without hardcoding any key names in the subroutine I use to parse the data struture. All I can pass to the subroutine is the data structure and the @keylist:

    @dev:/links:nydevnfs_links:/vol/links:0755:root:root:nfsvers=3,timeo=6 +00,re +trans=2 @dev:/links:rnap7750-s:/vol/links_c:0755:root:root:nfsvers=3,timeo=600 +,retr +ans=2 @dev:/home7:nydevnfs_home7:/vol/home7:0755:root:root:nfsvers=3,timeo=6 +00,re +trans=2 @dev:/home7:rnap7751-s:/vol/home7_c:0755:root:root:nfsvers=3,timeo=600 +,retr +ans=2 @dev:/home8:nydevnfs_home2:/vol/home2:0755:root:root:nfsvers=3,timeo=6 +00,re +trans=2 @dev:/home8:rnap2114-s:/vol/home2_c:0755:root:root:nfsvers=3,timeo=600 +,retr +ans=2
      To fix the first problem, just prepend % to the indicated reference variables.

      To the rest, I cannot say more than "Good luck".

      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

        Thanks ever so much for your help choroba I have made the changes you suggested and this is now working perfectly :-) Just one thing if you can help. In the sample data structure I posted there is a @dev tag in this and I need to get this value prepended to each line of output. I mustn't hardcode this though. I have other hashes of hashes defined under this whole @dev section which are called @build and @software (which both have loads of mount definitions in )and to each of the lines printed when I parse these I need to prepend the corresponding tag @build/@software. Would you be able to help me with what I need to do here please?

        Thanks alot for all your help. As regards prepended % to these variables. Please can you show me where I need to do this? I have tried doing this and I am still getting errors :-(

        Thanks alot for all your help. Can you show me where I need to prepend % please?