use strict; use Data::Dumper; my %H; while () { my $rootkey; my @elements; if (/Main/) { while () { $rootkey = "$1" if /^\s*Name\s*=\s*(.*)$/; unshift(@elements, "$1") if /^\s*(?:Action|Text)\s*=\s*(.*)$/; last if /---/; } } $H{$rootkey} = {@elements}; } my %G = process(\%H, 'Countries'); print Dumper(\%G); sub process { my ($href, $key) = @_; my %G; foreach my $k (keys %{$href->{$key}}) { $G{$key}{$k} = $href->{$key}{$k} =~ /^Find:\s+(.*)$/ ? {process(\%H, $1)} : $href->{$key}{$k}; } return %G; } __DATA__ Main Name = Countries End ... The rest of your data..