user3834663
user3834663

Reputation: 553

print JSON objects using perl

I am new to perl and i had written below snippet of code to get the JSON objects from the data. But the input data has both hashes and arrays, So how do i get those values for "id" which is an array ?

  use strict;
  use warnings;
  use Data::Dumper;
  use JSON

 my $data = '{"total":325,"id": [78,234,737,1253,1459,1733,2166,2653,2855,3133,3414,3538,3729,3905,3991,4110,4160,4536,4692,4701]}';

 print Dumper($data);
 my @hash_ref = from_json($data);

 foreach my $hash_scalar (@hash_ref) {

    foreach (keys %{$hash_scalar}) {
        print "$_ => ${$hash_scalar}{$_}\n";
        }
    }

Output Getting

#
$VAR1 = '{"total":325,"id": 
[78,234,737,1253,1459,1733,2166,2653,2855,3133,3414,3538,3729,3905,3991,4110,4160,4536,4692,4701]}';
id => ARRAY(0x2afee4c)
total => 325

Upvotes: 1

Views: 5704

Answers (3)

Polar Bear
Polar Bear

Reputation: 6798

Perhaps following code will cover your question in more complete extent.

NOTE: I've added a hash in data block as bonus

use strict;
use warnings;
use feature 'say';

use JSON;
use Data::Dumper;

my $debug = 0;

my $data = '{ "total":325,
              "id": [78,234,737,1253,1459,1733,2166,2653,2855,3133,3414,3538,3729,3905,3991,4110,4160,4536,4692,4701],
              "person": {
                "first": "John",
                "last": "Smith", 
                "age": 27, 
                "occupation": "accountant",
                "wife": "Maria Smith",
                "son": "Alex Smith",
                "daughter": "Samantha Smith",
                "dog": "Sparky",
                "hobby": "photography"
               }
            }';

say Dumper($data) if $debug;

my $json = from_json($data);

say Dumper($json) if $debug;

while( my($k,$v) = each %{$json} ) {
    say "Key: $k";
    if( ref $v eq 'ARRAY' ) {
        say "\tValue is ARRAY";
        for ( @{$v} ) { say "\t\t[$_]" }
    } elsif( ref $v eq 'HASH' ) {
        say "\tValue is HASH";
        while( my($hk,$hv) = each %{$v} ) {
            say "\t\t$hk => $hv";
        }
    } else {
        say "\tValue: $v";
    }
}

say '-' x 40;
say 'Element with index 5 is ' . $json->{id}[5];
say 'Name of the son      is ' . $json->{person}{son};
say 'Name of the daughter is ' . $json->{person}{daughter};

Output

Key: person
        Value is HASH
                son => Alex Smith
                occupation => accountant
                daughter => Samantha Smith
                age => 27
                wife => Maria Smith
                dog => Sparky
                last => Smith
                first => John
                hobby => photography
Key: id
        Value is ARRAY
                [78]
                [234]
                [737]
                [1253]
                [1459]
                [1733]
                [2166]
                [2653]
                [2855]
                [3133]
                [3414]
                [3538]
                [3729]
                [3905]
                [3991]
                [4110]
                [4160]
                [4536]
                [4692]
                [4701]
Key: total
        Value: 325
----------------------------------------
Element with index 5 is 1733
Name of the son      is Alex Smith
Name of the daughter is Samantha Smith

Upvotes: -1

brian d foy
brian d foy

Reputation: 132822

The id is a key in the hash reference you get back, and you want to grab its value, which is an array reference. You can either keep that as a reference or grab its elements right away:

#!perl
use v5.24;
use JSON qw(from_json);

my $data = '{"total":325,"id": [78,234,737]}';

my $json = from_json($data);

# get the hash key to get the hash value, which is an array reference
my $ids_array_ref = $json->{id};

# OR, use the postfix dereference to get the ids as a normal list
my @ids_array = $json->{id}->@*;

# OR, use the older circumfix notation (before Perl v5.24). These are all
# the same:
my @ids_array = @{ $json->{id} };
my @ids_array = @{ $ids_array_ref };
my @ids_array = @$ids_array_ref;

For example:

#!perl
use v5.24;
use JSON qw(from_json);

my $data = '{"total":325,"id": [78,234,737]}';

my $json = from_json($data);

foreach my $id ( $json->{id}->@* ) {
    say "Got id $id";
    }

This outputs:

Got id 78
Got id 234
Got id 737

But, you have to handle the other hash value types too. To decide how to print something, you have to check if it's a reference and what sort of reference it is (I ignore the other sorts here):

#!perl
use v5.24;
use JSON qw(from_json);

my $data = '{"total":325,"id": [78,234,737]}';

my $json = from_json($data);

foreach my $key ( keys $json->%* ) {
    print "$key: ";
    if( ref $json->{$key} eq 'ARRAY' ) {
        say join ' ', $json->{$key}->@*;
        }
    elsif( ref $json->{$key} ) { # all other reference types
        warn "I don't handle this yet"
        }
    else {
        say $json->{$key};
        }
    }

But, you might have deeper levels of nesting, so you'd need to think about that too if you want to output everything. If I know what keys I want, I don't try to go through everything in a general way. I go directly to want I want:

#!perl
use v5.24;
use JSON qw(from_json);

my $data = '{"total":325,"id": [78,234,737]}';

my $json = from_json($data);

say "id: ", join ' ', $json->{id}->@*;
say "total: ", $json->{total};

Your original code was doubly complicated. The result of from_json is the reference that represents the JSON data structure. That's a JSON object, which is what Perl calls a hash, so you get a hash reference back.

my $hash_ref = from_json( $data );

Your example almost worked because you got an array of one element, which is that hash reference. The other foreach then iterates over that one element. Get rid of that outer array and you get rid of the outer loop.

We cover references and data structures in Intermediate Perl, although the perldsc is good too. We have a long examples of deeply-nested and recursive data structures.

If you're new, you may want to start with Learning Perl, though.

Upvotes: 2

Matt Shin
Matt Shin

Reputation: 434

My Perl is getting rusty, but I think something like this should do the trick. You need to de-reference your array reference with another @{...} like @{${$hash_scalar}{$_}}.

use strict;
use warnings;
use Data::Dumper;
use JSON

my $data = '{"total":325,"id": [78,234,737,1253,1459,1733,2166,2653,2855,3133,3414,3538,3729,3905,3991,4110,4160,4536,4692,4701]}';

print Dumper($data);
my @hash_ref = from_json($data);

for my $hash_scalar (@hash_ref) {
    for my $key (keys(%{$hash_scalar})) {
        print("$key => @{${$hash_scalar}{$_}}\n");
    }
}

Upvotes: 0

Related Questions