Recursion does seem the natural way to tackle this given the heierachical structure of the data. Find out about recursion with accumulators (if it is new to you).
use JSON::XS;
use 5.12.0;
use Data::Dump qw(dd);
my $j =
'{ "/": { "type": "dir", "files": [ { "p": { "type": "dir-link", "sour
+ce": "/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", "fil
+es": [ { "project": { "type": "dir", "files": [] } } ] } }, { "vsa":
+{ "type": "dir", "files": [ { "project": { "type": "dir", "files": [
+{ "xa": { "type": "dir", "files": [ { "vuvua": { "type": "dir", "file
+s": [ { "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;
}
}
}