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

Hey All!

I have this hash:
my %foo = ( Info => [ { MakeEng => 1, MakeFre => 2, ModelEng => 3, ModelFre => 4, ModelYear => 5, }, { MakeEng => 6, MakeFre => 7, ModelEng => 8, ModelFre => 9, ModelYear => 0, }, ], VIN => { VINStatus => 'active', VechileDT => 'on', }, );
I want to parse through in and turn each main heading (Info,VIN) into tables with the next level keys will be the table fields.

I was going to use a foreach loop, but how can I tell the data is from an array or a hash??

Please help!

Replies are listed 'Best First'.
Re: Hash of Arrays of Hashes Parsing
by tcf22 (Priest) on Sep 17, 2003 at 19:47 UTC
    Try this:
    if(ref($reference) eq 'HASH'){ print 'Its a HASH reference'; ## Do Hash processing }elsif(ref($reference) eq 'ARRAY'){ print 'Its an ARRAY reference'; ## Do array processing }elsif(ref($reference)){ print 'Its a ' . ref($reference) . ' reference'; ## Handle invalid reference }else{ print "It isn't a reference"; ## Actual value, not a reference - do something }

    - Tom

      Thanks Tom!

      That was perfect.

      Cheers!
Re: Hash of Arrays of Hashes Parsing
by gryphon (Abbot) on Sep 17, 2003 at 20:24 UTC

    Greetings SmokeyB,

    I was bored (and I think I'm coming down with a fever, so coding is always fun) so I coded up some stuff for you. It's not good code, but it may help you get in the direction you're looking for. I made the assumption that "into tables" means "into HTML tables".

    #!/usr/bin/perl use strict; use warnings; my %foo = ( Info => [ { MakeEng => 1, MakeFre => 2, ModelEng => 3, ModelFre => 4, ModelYear => 5, }, { MakeEng => 6, MakeFre => 7, ModelEng => 8, ModelFre => 9, ModelYear => 0, }, ], VIN => { VINStatus => 'active', VechileDT => 'on', }, ); foreach my $table (keys %foo) { print '<h3>', $table, '</h3>', "\n"; print "<table>\n"; if (ref $foo{$table} eq 'HASH') { print '<tr><td>', $_, '</td><td>', $foo{$table}{$_}, "</td></tr>\n +" foreach (keys %{$foo{$table}}); } elsif (ref $foo{$table} eq 'ARRAY') { print '<tr>'; print '<td>', $_, '</td>' foreach (keys %{$foo{$table}[0]}); print "<tr>\n"; foreach my $row (@{$foo{$table}}) { print '<tr>'; print '<td>', $_, '</td>' foreach (values %{$row}); print "<tr>\n"; } } else { print "<tr><td>Badness. Something unexpected in %foo</td></tr>\n"; } print "</table>\n\n"; } exit;

    I don't know the extent of your project, but if you're looking for something long-term that's going to map into some kind of web reporting thing, you should definately take a look at HTML::Template. Using that, you could just muck around a little with your %foo and then just pass that into a template. Magic then happens.

    gryphon
    code('Perl') || die;

Re: Hash of Arrays of Hashes Parsing
by hmerrill (Friar) on Sep 17, 2003 at 20:37 UTC
    How about
    foreach my $key (keys %foo) { if ($key eq "Info") { print "I'm working with the Info array\n"; print "Table name is 'Info'\n"; ### each element of the Info array is a hash reference ### foreach my $info_hashref (@{$foo{'Info'}}) { while (my ($k, $v) = each %$info_hashref) { print "column name is $k, value is $v\n"; } } } else: print "Table name is 'VIN'\n"; while (my ($k, $v) = each %{$foo{'VIN'}}) { print "column name is $k, value is $v\n"; } } }
    Careful 'cause this is completely untested.

    HTH.
      Hey hmerrill,

      Thank-you, that would work fine, but it's very specific. The hash itself can be populated with a wide variety of keys and data, never really know exactly what will be returned at the time.

      What I ended up doing is the following:
      print "\t<tr>\n"; if (ref($data) eq 'ARRAY') { foreach my $array (@$data) { foreach my $value (keys %$array) { print "\t\t<td>$array->{$value}</td>\n"; } } } elsif ref($data) eq 'HASH') { foreach my $value (keys %$data) { print "\t\t<td>$data->{$value}</td>\n"; } } else { print "\t\t<td>Too Bad Sucka!</td>\n"; } print "\t</tr>\n";
      Cheers!
        Your solution looks fine, but I have to comment on one thing - the naming of your variables. This is just personal preference, but IMHO it makes your code much clearer and much more readable if you name the variables - especially references - what they are, or what they contain.

        Here is your example with some of the variables renamed:
        print "\t<tr>\n"; if (ref($data) eq 'ARRAY') { ### Since each element of the array is a hash reference, ### name it so you know what it is. #foreach my $array (@$data) foreach my $hashref (@$data) { #foreach my $value (keys %$array) foreach my($key,$value) (each %$hashref) { #print "\t\t<td>$array->{$value}</td>\n"; print "\t\t<td>$value</td>\n"; } } } elsif ref($data) eq 'HASH') { #foreach my $value (keys %$data) foreach my($key,$value) (each %$data) { #print "\t\t<td>$array->{$value}</td>\n"; print "\t\t<td>$value</td>\n"; } } else { print "\t\t<td>Too Bad Sucka!</td>\n"; } print "\t</tr>\n";
Re: Hash of Arrays of Hashes Parsing
by hardburn (Abbot) on Sep 17, 2003 at 19:35 UTC

    ref

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated