use JSON::XS; use 5.12.0; use Data::Dump qw(dd); my $j = '{ "/": { "type": "dir", "files": [ { "p": { "type": "dir-link", "source": "/nfs/data/project", "files": [ { "xa": { "type": "dir", "files": [ { "tools": { "type": "dir", "files": [ { "sd": { "type": "dir", "files": [ { "su2av": { "type": "dir", "files": [ { "duf": { "type": "dir", "files": [ { "0.4.0": { "type": "dir-link", "source": "/nfs/vsa/project/xa/vuvua/su2av", "files": [ { "bin": { "type": "dir", "files": [ { "duf": { "type": "link-file", "source": ".run" } }, { ".run": { "type": "file" } } ] } } ] } } ] } } ] } } ] } } ] } } ] } } ] } }, { "nfs": { "type": "dir", "files": [ { "data": { "type": "dir", "files": [ { "project": { "type": "dir", "files": [] } } ] } }, { "vsa": { "type": "dir", "files": [ { "project": { "type": "dir", "files": [ { "xa": { "type": "dir", "files": [ { "vuvua": { "type": "dir", "files": [ { "su2av": { "type": "dir", "files": [] } } ] } } ] } } ] } } ] } } ] } } ] } }'; my $obj = decode_json($j); dd $obj; my %special_key = map { $_ => 1 } qw/type files source/; find_paths($obj, []); sub find_paths { my ($x, $paths) = @_; if (ref $x eq 'HASH') { while (my ($k, $v) = each %$x) { if(exists $special_key{$k}) { if($k eq 'files') { find_paths($v, $paths); } elsif( $k eq 'type' && $v eq 'file' ) { say join '/', @$paths; } } else { # a dir or file name # store it and continue find_paths($v, [@$paths, $k]); } } } elsif (ref($x) eq 'ARRAY') { if (scalar @$x > 0) { foreach my $node (@$x) { find_paths($node, $paths); } } else { say join '/', @$paths; } } }