satzbu has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks i have a code to replace a hash key against another hash value this is my code

use Data::Dumper; use XML::Simple; my %xhash = ('a' => { 'b' => { 'e' => 'E', 'c' => 'C', 'content' => 'B', } , 'content' => 'A', 'd' => 'D' }); my %c_hash=('a' => { 'addval' => { 'b' => { 'addval' => { 'e' => { 'addv +al' => {}, 'repv +al' => '5' }, 'c' => { 'addv +al' => {}, 'repv +al' => '3' } }, 'repval' => '2' }, 'd' => { 'addval' => {}, 'repval' => '4' } }, 'repval' => '1' }); my %repl; # lookup table: a => 1, etc. traverse(\%c_hash, sub { my ($key, $val) = @_; $repl{$key} = $val; }, "collect" ); #print Dumper \%repl; # debug traverse(\%xhash, sub { my ($key, $val, $href) = @_; if (exists $repl{$key}) { my $newkey = $repl{$key}; $href->{$newkey} = $val; delete $href->{$key}; } }, "replace" ); print Dumper \%xhash; sub traverse { my ($hash, $callback, $mode) = @_; return unless ref($hash) eq "HASH"; for my $key (keys %$hash) { my $val = $hash->{$key}; if (ref($val) eq "HASH") { traverse($val, $callback, $mode); if ($mode eq "collect") { if (exists $val->{repval}) { $callback->($key, $val->{repval}); } } } if ($mode eq "replace") { $callback->($key, $val, $hash); } } } _output_ $VAR1 = { '1' => { '4' => 'D', 'content' => 'A', '2' => { '3' => 'C', 'content' => 'B', '5' => 'E' } } };

when i change my input as like below and want to get the output like below

_REQUIRED INPUT_ my %xhash = ('a' =>[ { 'b' => [ { 'e' =>['E','V'], 'c' => ['C'], 'content' => ['B'], } ], 'content' => ['A'], 'd' => ['D'] }]); _REQUIRED OUTPUT_ $VAR1 = { '1' => [{ '4' => ['D'], 'content' => ['A'], '2' => [{ '3' => ['C'], 'content' => ['B'], '5' => ['E','V'] }] }] };

i want the output like this please help me what changes i want to make on my code

Replies are listed 'Best First'.
Re: Hash handling error
by almut (Canon) on Apr 17, 2010 at 07:02 UTC

    ( for reference: for loop error )

    As every value in your %xhash structure is now wrapped in an array (including its hashes), you'd need to adapt the traverse() routine to dive into those arrays. For example:

    sub traverse { my ($hash, $callback, $mode) = @_; traverse($hash->[0], $callback, $mode) if ref($hash) eq "ARRAY"; + # <--- return unless ref($hash) eq "HASH"; for my $key (keys %$hash) { my $val = $hash->{$key}; if (ref($val)) { traverse($val, $callback, $mode); if ($mode eq "collect") { if (exists $val->{repval}) { $callback->($key, $val->{repval}); } } } if ($mode eq "replace") { $callback->($key, $val, $hash); } } }

    Output:

    $VAR1 = { '1' => [ { '4' => [ 'D' ], 'content' => [ 'A' ], '2' => [ { '3' => [ 'C' ], 'content' => [ 'B' ], '5' => [ 'E', 'V' ] } ] } ] };

    (Also, as "$hash" has now become a misnomer, I'd change it to something more generic, like $node, or some such... but I left that for you to do :)

Re: Hash handling error
by toolic (Bishop) on Apr 17, 2010 at 14:14 UTC
    use XML::Simple;
    This indicates that you are probably dealing with XML files, although you don't seem to call any XML::Simple functions. One of the benefits of using XML::Simple is that is forces you to learn to navigate arbitrarily complex Perl data structures.

    If you are parsing XML and you want to abstract some of those gory details away, I recommend switching to another parser, such as XML::Twig. It is sometimes easier to call methods to handle elements and attributes.

Re: Hash handling error
by ikegami (Patriarch) on Apr 17, 2010 at 07:00 UTC

    Sorry, I just have a second to spend on this. If I understood correctly, somewhere you have

    $href->{$k} = $v;
    where you want
    push @{ $href->{$k} }, $v;
    which is short for
    push @{ $href->{$k} ||= [] }, $v;