Perl - JSON

Hi All,

I’m trying to do a bit of JSON manipulation in Perl, and I’ve got the following object (via dumper):

List: $VAR1 = [
          {
            'servers' => [
                           {
                             'name' => 'Test01',
                             'id' => 10010915
                           },
                           {
                             'name' => 'Test02',
                             'id' => 10010916
                           }
                         ]
          }
        ];

And I’m trying to use the following Perl to look and get at the data:


        print "List: ".Dumper(\\@list);
        %listHash = $list[0]->{$what}[0]; ## This is line 57! ##
            while(($key, $value) = each(%listHash)) {
                print "$key, $value\
!";
        }

But I’m getting errors like this:

Reference found where even-sized list expected at api.pm line 57 (#1)

What have I been doing wrong?

@list is an array of hashes. It only has one entry. In reality it is a array of hash references.

$list[0] gives you the first (and only) hash reference in the array.

Each of the hashes referenced have a single key/value pair where the key is ‘servers’. The value is and array. In reality a reference to an array.

So $list[0]->{‘servers’} returns a reference to the array. This array is an array of hashes, in fact an array of hash references. To access the first element we need

$list[0]->{‘servers’}->[0]

But this returns a reference to a hash not a hash, so we need to cast it to a hash thus

%{$list[0]->{‘servers’}->[0]}

So you line

%listHash = $list[0]->{$what}[0];

needs to be

%listHash = %{$list[0]->{$what}->[0]}

provided $what is ‘servers’.

Hi Phillip,

Thanks for the help, %listHash = %{$list[0]->{$what}->[0]} did allow me to access different members of the array of hash references, but I was unable to figure out how to loop it, any suggestions? :S

my $i = 0;
foreach my $entry (@{$list[0]->{$what}}) {
	%listHash = %{$entry};
	$i++;
	while(($key, $value) = each(%listHash)) {
	    print "${key}_$i, $value\
";
	}
}

use an outer loop to iterate through the elements of the array.

Another way:

use strict;
use warnings;
use 5.010;
 
my $data = [
          {
            'servers' => [
                           {
                             'name' => 'Test01',
                             'id' => 10010915
                           },
                           {
                             'name' => 'Test02',
                             'id' => 10010916
                           }
                         ]
          }
];
 
my $server_aref = $data->[0]->{servers};
 
for my $href (@$server_aref) {
  say "name = $href->{name}, id = $href->{id}";
}

--output:--
name = Test01, id = 10010915
name = Test02, id = 10010916
 

Thanks for all the help Philip and 7stud, I’ve now got my code doing what I need, just one problem, this:


    %data = (
        'id' => @list->[0]->{'image'}->{'id'},
        'name' => @list->[0]->{'image'}->{'name'},
        'status' => @list->[0]->{'image'}->{'status'},
        'progress' => @list->[0]->{'image'}->{'progress'}
        );

Is generating this warning:


Using an array as a reference is deprecated at api.pm line 106 (#1)

How should I be getting the contents out?

Sorry to keep asking stupid questions!

RandomCake

You should read perlreftut if you are having trouble with reference syntax.

use strict;
use warnings;
use 5.010;
 
my @list = (10, 20, 30);
say $list[2];

--output:--
30
 
my $aref = \\@list;
say @{$aref}[2];

--output:--
30


say $aref->[2];

--output:--
30


say @list->[2]   

--output:--
Using an array as a reference is deprecated at prog.pl line 11.



The left side of the arrow has to be a reference, and reference variables begin with a $.

Whoops. It looks like I need to reread perlreftut myself. The following is not really correct:

use strict;
use warnings;
use 5.010;
 
my @list = (10, 20, 30);
my $aref = \\@list;

say @{$aref}[2];  #<--*****
  1. When you index into an array, you get back a single element, which must be stored in a variable that starts with a $.

  2. The reason I didn’t get an error there is because perl also lets you create subsets of an array using ‘slice’ syntax:

use strict;
use warnings;
use 5.010;
 
my @list = (10, 20, 30);
my @subset = @list[0, 2];
say "@subset";

--output:--
10 30

Note that an array slice returns an array. So in my faulty line here:

say @{$aref}[2];  

@{$aref}[2] returns an ‘array slice’ with one element, which is actually an array containing one element, and say/print can take an array as an argument, and it will print out each element of the array.

  1. I realy should have wrote that line as:
say ${$ref}[2];

The leading $ tells you that a single value is being returned from the array. Then as perlreftut tells us, you can always use an array reference surrounded by curly braces instead of the letters of an array name. For instance, if you normally access an array element like this:

my $result = $list[2];

you can subsitute {$aref} in place of ‘list’, giving you this:

my $result = ${$aref}[2];