user3248687
user3248687

Reputation: 1

How to convert a multi dimensional HASH into a CSV file in PERL?

Hello I'm retrieving data from a XMLRPC API via PERL and end up with an HASH (actually I believe the correct term here would be array within an array) which I partially want to convert into a CSV file.

As a basic overview here is what I am doing:

my $server = XMLRPC::Lite
    ->proxy('https://myhost/api');
my $session = $server->login(foo)
    ->result;
my @tempArr = $server->call(foobar)->result;

Afterwards a:

print @tempArr;

results in:

HASH(0x23c0330)

If I dump the HASH content via Data::Dumper:

print Dumper(\@tempArr);

then I receive the following structure of the array:

$VAR1 = [
      {
        'table' => [
                   [
                     'abc',
                     'def',
                     'ghi',
                     'jkl'
                   ],
                   [
                     'abc',
                     'def',
                     'fed',
                     'cba'
                   ],
                 ],
        'columns' => [
                     'field1',
                     'field2',
                     'field3',
                     'field4',
                   ]
      }
    ];

Now I would like to write all items from 'table' into a CSV formated file. So basically in this case:

abc,def,ghi,jkl
abc,def,fed,cba

I was playing around with Text::CSV::Slurp for a while, but didn't really understand how to handle it for arrays within arrays:

my $csv = Text::CSV::Slurp->create( input => \@tempArr);
my $file = "/path/output.csv";
open( FH, ">$file" ) || die "Couldn't open $file $!";
print FH $csv;
close FH;

I only came up with a csv file of the following content:

columns,table
ARRAY(0x23c01b0),ARRAY(0x25a944c)

Any suggestions on how to approach this issue would be appreciated. Currently I've decided to go back and read about arrays and hashes in PERL in general, as I seem to lack a lot of fundamental understanding on the matter.

Upvotes: 0

Views: 925

Answers (3)

tangent
tangent

Reputation: 561

It seems that result() is returning a hash reference not an array, so change that line to:

my $result = $server->call(foobar)->result;

Then transform the result into the format required by Text::CSV::Slurp

my $cols = $result->{'columns'};
my $rows = $result->{'table'};
my @idx  = 0 .. @$cols - 1;
my @array_of_hashes;
for my $row (@$rows) {
    my %hash = map { $cols->[$_] => $row->[$_] } @idx;
    push(@array_of_hashes,\%hash);
}
my $csv = Text::CSV::Slurp->create(
    input => \@array_of_hashes,
    field_order => $cols
);

Upvotes: 1

ooga
ooga

Reputation: 15501

This will produce your csv file directly from your data structure:

for my $arr (@{$$VAR1[0]{'table'}}) {
    my $last_elem = pop(@$arr);
    for my $elem (@$arr) { print("$elem,"); }
    print("$last_elem\n");
}

Upvotes: 0

Oesor
Oesor

Reputation: 6652

Text::CSV::Slurp operates on arrayrefs of the following format (both for how it parses and for what it takes to write back to CSV:)

$VAR1 = [ { field1 => 'abc',
            field2 => 'def',
            field3 => 'ghi',
            field4 => 'jkl',
          },
          { field1 => 'abc',
            field2 => 'def',
            field3 => 'fed',
            field4 => 'cba',
          },
    ];

Transform your response into that type of format.

As it operates now, Text::CSV::Slurp is treating the table and columns first level keys as the data field names, then stringifying the contained arrayrefs and using them as a value.

Upvotes: 1

Related Questions