0.foo.bar = 0foobar 0.foo.baz = 0foobaz 1.foo = 1foo equates to: [ { foo => { bar => '0foobar', baz => '0foobaz' } }, { foo => '1foo' } ] #### >.foo.bar = 0foobar <.foo.baz = 0foobaz >.foo = 1foo #### use strict; use warnings; use Data::Diver qw#DiveVal DiveError#; use Data::Dumper qw#Dumper#; $/ = qq#\r\n#; my $state = { }; my $ref = undef; while ( my $line = ) { next if ( $line =~ qr#^(\#|\s*$)# ); # ignore line if comment or blank. chomp $line; # remove newline. my ( $selector, $value ) = split qr#\s*=\s*#, $line; # (selector)=(value). todo: unless escaped. next if ( not defined $selector ); # ignore line if no selector. my @selector = split qr#\.#, $selector; # (one).(two).(three)... todo: unless escaped. $ref //= ( $selector[0] =~ qr#^([><]|\d+)$# ) ? [ ] : { } ; _dive( $ref, \@selector, $value ); } print Dumper $state, $ref; sub _dive { my ( $ref, $selector, $value ) = @_; return if ( not defined $ref or not defined $selector or not scalar @$selector ); # return if no ref or no selectees. my @selector_b = qw##; for my $selectee ( @$selector ) { if ( $selectee =~ qr#^([><])$# ) # if incognito selectee. todo: unless escaped. { my $selector_b = join q#.#, @selector_b; if ( $1 eq q#># ) # incognito selectee is of increment type. { if ( defined $state->{$selector_b} ) # we have seen this state before. { push @selector_b, $state->{$selector_b} += 1; # push current index + 1. } else { push @selector_b, $state->{$selector_b} = 0; # push 0 (first) index. } } elsif ( $1 eq q#<# ) # incognito selectee is of maintain type. { push @selector_b, $state->{$selector_b} //= 0; # push current index or 0 (first) index. } } else # else non inconito selectee. { push @selector_b, $selectee; # push selectee. } } 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 #### $VAR1 = { '2.interests' => 1, '' => 2, '2.interests.0' => 1, '0.interests' => 1, '1.interests' => 2 }; $VAR2 = [ { 'interests' => [ 'programming', 'cycling' ], 'location' => 'uk', 'name' => 'john' }, { 'interests' => [ 'knitting', 'tennis', 'dancing' ], 'location' => '', 'name' => 'laura' }, { 'interests' => [ [ 'dogs', 'horses' ], 'cars' ], 'location' => 'canada', 'name' => undef } ];