$data = { foo => 3, bar => [ qw/ this that 3 / ], 3 => undef, baz => { trois => 3, quatre => [ qw/ 1 2 3 4 / ], } }; ok $paths = path( $data, 3 ), 'Fetching paths for matching data should succeed'; my @expected = sort ( '{bar}[2]', '{baz}{trois}', '{baz}{quatre}[2]', '{foo}' ); $paths = [ sort @$paths ]; is_deeply $paths, \@expected, '... and we should be able to match complex data structures'; foreach my $path (@$paths) { is eval "\$data->$path", 3, '... and each element should have the correct value'; } #### use Scalar::Util 'reftype'; my %path = ( ARRAY => \&_array_path, HASH => \&_hash_path, ); sub path { my ( $data, $search ) = @_; my $type = reftype $data; my $find_paths = $path{$type}; return $find_paths->( $data, $search ); } sub _array_path { my ( $data, $search ) = @_; my @paths; foreach my $i (0 .. $#$data) { my $item = $data->[$i]; my $type = reftype $item; my $current_index = "[$i]"; if ( !$type && $item eq $search ) { # XXX push @paths => $current_index; } elsif ( my $find_paths = $path{$type} ) { my @current_paths = map { "$current_index$_" } @{ $find_paths->( $item, $search ) }; push @paths => @current_paths; } } return \@paths; } sub _hash_path { my ( $data, $search ) = @_; my @paths; foreach my $key (keys %$data) { my $item = $data->{$key}; my $type = reftype $item; my $current_key = "{$key}"; if ( !$type && $item eq $search ) { # XXX push @paths => $current_key; } elsif ( my $find_paths = $path{$type} ) { my @current_paths = map { "$current_key$_" } @{ $find_paths->( $item, $search ) }; push @paths => @current_paths; } } return \@paths; }