Here's my guess as to what you want, at least it gets the directories you showed.
#!/usr/bin/perl
use strict; # https://perlmonks.org/?node_id=11130470
use warnings;
use JSON::PP;
my $j = '{ "/": { "type": "dir", "files": [ { "p": { "type": "dir-link
+",
"source": "/nfs/data/project", "files": [ { "xa": { "type": "dir", "fi
+les":
[ { "tools": { "type": "dir", "files": [ { "sd": { "type": "dir", "fil
+es": [ {
"su2av": { "type": "dir", "files": [ { "duf": { "type": "dir", "files"
+: [ {
"0.4.0": { "type": "dir-link", "source": "/nfs/vsa/project/xa/vuvua/su
+2av",
"files": [ { "bin": { "type": "dir", "files": [ { "duf": { "type": "li
+nk-file",
"source": ".run" } }, { ".run": { "type": "file" } } ] } } ] } } ] } }
+ ] }
} ] } } ] } } ] } } ] } }, { "nfs": { "type": "dir", "files": [ { "dat
+a": {
"type": "dir", "files": [ { "project": { "type": "dir", "files": [] }
+} ] }
}, { "vsa": { "type": "dir", "files": [ { "project": { "type": "dir",
+"files":
[ { "xa": { "type": "dir", "files": [ { "vuvua": { "type": "dir", "fil
+es": [ {
"su2av": { "type": "dir", "files": [] } } ] } } ] } } ] } } ] } } ] }
+} ] } }';
my $obj = decode_json($j);
my $alltypesref = findtypes( $obj );
use Data::Dump 'dd'; dd $alltypesref;
sub removeprefixes
{
local $_ = join "\n", grep $_ ne '/', (sort @_), '';
s/^(\N*)\n(?=.*^\1\/)//gm;
split /\n/;
}
sub findtypes
{
my ($obj) = @_;
my $types = {};
findpath($obj, '', $types);
$types->{dir} = [ removeprefixes @{ $types->{dir} } ];
return $types;
}
sub findpath
{
my ($obj, $path, $types) = @_;
for my $name ( keys %$obj )
{
my $info = $obj->{$name};
push @{ $types->{$info->{type}} }, my $new = "$path/$name" =~ tr[/
+][]sr;
findpath( $_, $new, $types ) for @{ $info->{files} };
}
}
Outputs:
{
"dir" => [
"/nfs/data/project",
"/nfs/vsa/project/xa/vuvua/su2av",
"/p/xa/tools/sd/su2av/duf/0.4.0/bin",
],
"dir-link" => ["/p", "/p/xa/tools/sd/su2av/duf/0.4.0"],
"file" => ["/p/xa/tools/sd/su2av/duf/0.4.0/bin/.run"],
"link-file" => ["/p/xa/tools/sd/su2av/duf/0.4.0/bin/duf"],
}