#!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11111952 use warnings; use List::Util qw( none ); use Data::Dump qw( dd ); sub subtree { my ($key, $tree) = @_; if( ref $tree eq 'ARRAY' ) { my @items = map [ subtree( $key, $_ ) ], @$tree; return +(none { $_->[0] } @items ) ? ( 0, []) : ( 1, [ map { $_->[0] ? $_->[1] : undef } @items ] ); } elsif( ref $tree eq 'HASH' ) { my @wanted; for my $k ( sort keys %$tree ) { if( $k eq $key ) { push @wanted, [ 1, $k => $tree->{$k} ] } else { my ( $w, $t ) = subtree( $key, $tree->{$k} ); $w and push @wanted, [ $w, $k => $t ]; } } return @wanted > 0, +{ map { @{ $_ }[1, 2] } @wanted }; } else { return 0, $tree } } sub pathforkey { my ($key, $tree, $sofar) = @_; if( ref $tree eq 'HASH' ) { return map { $key eq $_ ? $sofar . "{$_}" : (), pathforkey( $key, $tree->{$_}, $sofar . "{$_}" ) } sort keys %$tree; } elsif( ref $tree eq 'ARRAY' ) { return map { pathforkey( $key, $tree->[$_], $sofar . "[$_]" ) } 0 .. $#$tree; } else { return () } } my $tree = gettree(); dd 'original tree', $tree; print "\n"; my ($want, $subtree) = subtree( 'field', $tree ); dd "the subtree for 'field' ", $subtree; print "\nall paths to key 'field' :\n"; print "$_\n" for pathforkey( 'field', $tree, '' ); sub gettree # slightly reduced... { my $tree = { 'cookies' => { '_AVESTA_ENVIRONMENT' => 'prod', '_mcid' => '1.340667ccb3eb6552450356561ab6bd92.' }, 'error' => '400 Bad Request', 'content' => { 'detail' => 'The resource specific details, \'errors\' array.', 'errors' => [ { 'message' => 'This value of type object.', 'field' => 'merge_fields' } ], 'status' => 400, 'title' => 'Invalid Resource', 'type' => 'http://developer.mailchimp.', 'instance' => '59edf1fc-ed93-4a40-ba23-1f0af24a6eb3' }, 'code' => '400' }; }