in reply to Parsing through a menu hash.

You could do something like this, though your output will of course need to be somewhat different:
use strict; use warnings; my ($d, $k1, $k2, $k3); while (<DATA>) { chomp; @_ = split /\:/; push @{$d->{$_[0]}{$_[1]}{$_[2]}}, $_[3]; } for $k1 (keys %$d) { for $k2 (keys %{$d->{$k1}}) { for $k3 (keys %{$d->{$k1}{$k2}}) { for (@{$d->{$k1}{$k2}{$k3}}) { print "$k1:$k2:$k3:$_\n"; } } } } __DATA__ category1:category2:category3:options categorya:categoryb:categoryc:more options categoryd:categorye:categoryf:even more options
Or, slightly more complicated:
use strict; use warnings; my ($d, $k1, $k2, $k3, $p1, $p2, $p3); while (<DATA>) { chomp; @_ = split /\:/; push @{$d->{$_[0]}{$_[1]}{$_[2]}}, $_[3]; } for $k1 (keys %$d) { $p1 = $d->{$k1}; for $k2 (keys %$p1) { $p2 = $p1->{$k2}; for $k3 (keys %$p2) { $p3 = $p2->{$k3}; for (@$p3) { print "$k1:$k2:$k3:$_\n"; } } } } __DATA__ category1:category2:category3:options categorya:categoryb:categoryc:more options categoryd:categorye:categoryf:even more options