use strict; use warnings; use Data::Diver qw( DiveVal DiveError ); use Data::Dumper qw( Dumper ); my $state = { }; my $ref = [ ]; my $prefix = '<'; while () { chomp; next if /^\s*#.*$/; if (/^\s*$/) { $prefix = '>'; next; }; my ($selector, $value) = split /\s*=\s*/; next unless defined $selector; my @selector = split /\./, $selector =~ s/\.$/.>/r; unshift(@selector, $prefix) unless $selector =~ /^[><]\./; _dive( $ref, \@selector, $value ); $prefix = '<'; } print Dumper $ref; sub _dive { my ( $ref, $selector, $value ) = @_; return unless defined $ref and defined $selector and scalar @$selector; my @selector_b; for ( @$selector ) { if ( /^(>|<|)$/ ) { my $selector_b = join '.', @selector_b; if ( $1 eq '<') { push @selector_b, $state->{$selector_b} //= 0; } else { $state->{$selector_b} += defined $state->{$selector_b} ? 1 : 0; push @selector_b, $state->{$selector_b}; } } else { push @selector_b, $_; } } DiveVal( $ref, @selector_b ) = $value; my ( $error ) = DiveError( ); $error and warn $error; return 1; } __DATA__ name = john location = uk interests. = programming interests. = cycling name = laura location = interests. = knitting interests. = tennis interests. = dancing name location = canada interests.. = dogs interests.<. = horses interests. = cars # test.error = blah