my $next = hash_walker(\%data); while (my @row = $next->()) { print join(',', @row), "\n"; } sub hash_walker { my ($href) = @_; die "Not a hash ref" if ref($href) ne 'HASH'; my (@ref, @key) = ($href, ()); while (ref($href) eq 'HASH') { my ($key, $val) = each %$href; push @key, $key; push @ref, $val; $href = $val; } my ($val, $done) = (pop @ref, undef); return sub { return () if $done; my @row = (@key, $val); my ($k, $v) = each %{$ref[-1]}; if (defined $k) { ($key[-1], $val) = ($k, $v); return @row; } my $idx = $#ref; while ($idx--) { my ($k, $v) = each %{$ref[$idx]}; next if ! defined $k; $key[$idx] = $k; $ref[$idx + 1] = $v; for ($idx + 1 .. $#ref) { my ($k, $v) = each %{$ref[$_]}; $key[$_] = $k; $ref[$_ + 1] = $v; } $val = pop @ref; return @row; } $done = 1; return @row; }; } #### output_hash(\%data); sub output_hash { my ($href) = @_; die "Not a hashref" if ref($href) ne 'HASH'; my (@work, @row) = ($href, ()); while (@work) { my $item = pop @work; my ($k, $v) = each %$item; next if ! defined $k; if (ref($v) eq 'HASH') { push @work, $item, $v; $row[$#work - 1] = $k; next; } push @work, $item; print join(',', @row, $k, $v), "\n"; } }