Reputation: 419
i'm trying to create a test module to test json encoding. i am having issues creating variables that will output correctly with the json encode/decode. if i use just the $cat_1 in the @cats array, it will work fine. however, using both, it prints out "HASH(..." as you can see below.
use strict;
use JSON;
use Data::Dump qw( dump );
my $cat_1 = {'name' => 'cat1', 'age' => '6', 'weight' => '10 kilos', 'type' => 'siamese'};
my $cat_2 = {'name' => 'cat2', 'age' => '10', 'weight' => '13 kilos', 'type' => 'siamese'};
my @cats;
push(@cats, $cat_1);
push(@cats, $cat_2);
my $dog_1 = {'name' => 'dog1', 'age' => '7', 'weight' => '20 kilos', 'type' => 'siamese'};
my $dog_2 = {'name' => 'dog2', 'age' => '5', 'weight' => '15 kilos', 'type' => 'siamese'};
my @dogs;
push(@dogs, $dog_1);
push(@dogs, $dog_2);
my $pets = {'cats' => @cats, 'dogs' => @dogs};
my $a = { 'id' => '123', 'name' => 'Joe Smith', 'city' => "Chicago", 'pets' => $pets };
my $json = JSON->new->allow_nonref;
my $encoded = $json->encode($a);
my $decoded = $json->decode( $encoded );
print "\ndump cat_1\n";
dump $cat_1;
print "\ndump cats\n";
dump @cats;
print "\n\nOriginal\n";
dump $a;
print "\n\n";
print "Encoded\n";
print $encoded;
print "\n\n";
print "Decoded\n";
dump $decoded;
print "\n\n";
output
dump cat_1
{ age => 10, name => "cat1", type => "siamese", weight => "10 kilos" }
dump cats
(
{ age => 10, name => "cat1", type => "siamese", weight => "10 kilos" },
{ age => 10, name => "cat2", type => "siamese", weight => "3 kilos" },
)
Original
{
city => "Chicago",
id => 123,
name => "Joe Smith",
pets => {
"cats" => { age => 10, name => "cat1", type => "siamese", weight => "10 kilos" },
"HASH(0x176c3170)" => "dogs",
"HASH(0x1785f2d0)" => { age => 10, name => "dog2", type => "siamese", weight => "3 kilos" },
},
}
Encoded
{"city":"Chicago","pets":{"HASH(0x1785f2d0)":{"weight":"3 kilos","name":"dog2","type":"siamese","age":"10"},"cats":{"weight":"10 kilos","name":"cat1","type":"siamese","age":"10"},"HASH(0x176c3170)":"dogs"},"name":"Joe Smith","id":"123"}
Decoded
{
city => "Chicago",
id => 123,
name => "Joe Smith",
pets => {
"cats" => { age => 10, name => "cat1", type => "siamese", weight => "10 kilos" },
"HASH(0x176c3170)" => "dogs",
"HASH(0x1785f2d0)" => { age => 10, name => "dog2", type => "siamese", weight => "3 kilos" },
},
}
Upvotes: 1
Views: 2238
Reputation: 567
The problem is in the creation of $pets:
my $pets = {'cats' => @cats, 'dogs' => @dogs};
Is roughly equivalent to:
my $pets = {'cats', {name => 'cat1', ...}, {name => 'cat2', ...},
'dogs', {name => 'dog1', ...}, {name => 'dog2, ...} };
Which is the same as:
my $pets = {
'cats' => {name => 'cat1', ...},
{name => 'cat2'}, => 'dogs',
{name => 'dog1', ...}, => {name => 'dog2}
};
You want to use ArrayRefs:
my $pets = {'cats' => \@cats, 'dogs' => \@dogs};
Which is:
my $pets = {
'cats' => [
{name => 'cat1', ...},
{name => 'cat2', ...},
],
'dogs' => [
{name => 'dog1', ...},
{name => 'dog2', ...},
],
};
Which is also how you could declare the whole data structure at once.
Upvotes: 6
Reputation: 118605
This line
my $pets = {'cats' => @cats, 'dogs' => @dogs};
is a red flag. It's valid Perl, but it's not doing what you would expect. Perl will flatten your lists in this construction, so if @cats
contains ($cat_1,$cat_2)
and @dogs
containts ($dog_1,$dog_2)
, your expression is parsed as
my $pets = { 'cats', $cat_1, $cat_2, 'dogs', $dog_1, $dog_2 };
which is like
my $pets = { 'cats' => $cat_1, $cat_2 => 'dogs', $dog_1 => $dog_2 }
with the hash references $cat_2
and $dog_1
getting stringified before being used as hash keys.
Hash values must be scalar values, not arrays. But array references are OK. Try:
my $pets = {'cats' => \@cats, 'dogs' => \@dogs};
Upvotes: 7