Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decoding and using JSON data in Perl

Tags:

json

perl

I am confused about accessing the contents of some JSON data that I have decoded. Here is an example

I don't understand why this solution works and my own does not. My questions are rephrased below

my $json_raw = getJSON(); 
my $content  = decode_json($json_raw);
print Data::Dumper($content);

At this point my JSON data has been transformed into this

$VAR1 = { 'items' => [ 1, 2, 3, 4 ] };

My guess tells me that, once decoded, the object will be a hash with one element that has the key items and an array reference as the value.

$content{'items'}[0]

where $content{'items'} would obtain the array reference, and the outer $...[0] would access the first element in the array and interpret it as a scalar. However this does not work. I get an error message use of uninitialized value [...]

However, the following does work:

$content->{items}[0]

where $content->{items} yields the array reference and [0] accesses the first element of that array.

Questions

  • Why does $content{'items'} not return an array reference? I even tried @{content{'items'}}, thinking that, once I got the value from content{'items'}, it would need to be interpreted as an array. But still, I receive the uninitialized array reference.

  • How can I access the array reference without using the arrow operator?

like image 922
donsiuch Avatar asked Sep 20 '14 15:09

donsiuch


People also ask

What is decoding in JSON?

Decode(String, Type) Converts data in JavaScript Object Notation (JSON) format into a data object of a specified type. Decode<T>(String) Converts data in JavaScript Object Notation (JSON) format into the specified strongly typed data list.

What is JSON encoding and decoding?

Source code: Lib/json/__init__.py. JSON (JavaScript Object Notation), specified by RFC 7159 (which obsoletes RFC 4627) and by ECMA-404, is a lightweight data interchange format inspired by JavaScript object literal syntax (although it is not a strict subset of JavaScript 1 ).

How do you decode a JSON string?

Decoding JSON data is as simple as encoding it. You can use the PHP json_decode() function to convert the JSON encoded string into appropriate PHP data type.

What is JSON data parsing?

JSON parsing is the process of converting a JSON object in text format to a Javascript object that can be used inside a program. In Javascript, the standard way to do this is by using the method JSON. parse() , as the Javascript standard specifies.


2 Answers

Beginner's answer to beginner :) Sure not as profesional as should be, but maybe helps you.

use strict;    #use this all times
use warnings;  #this too - helps a lot!
use JSON;

my $json_str = '    { "items" : [ 1, 2, 3, 4 ] }    ';
my $content = decode_json($json_str);

You wrote:

My guess tells me that, once decoded, the object will be a hash with one element that has the key items and an array reference as the value.

Yes, it is a hash, but the the decode_json returns a reference, in this case, the reference to hash. (from the docs)

expects an UTF-8 (binary) string and tries to parse that as an UTF-8 encoded JSON text, returning the resulting reference.

In the line

my $content = decode_json($json_str);

you assigning to an SCALAR variable (not to hash).

Because you know: it is a reference, you can do the next:

printf "reftype:%s\n", ref($content);
#print: reftype:HASH       ^   
           #therefore the  +------- is a SCALAR value containing a reference to hash

It is a hashref - you can dump all keys

print "key: $_\n" for keys %{$content}; #or in short %$content
#prints: key: items

also you can assing the value of the "items" (arrayref) to an scalar variable

my $aref = $content->{items};   #$hashref->{key}
#or
#my $aref = ${$content}{items}; #$hash{key}

but NOT

#my $aref = $content{items};    #throws error if "use strict;"
#Global symbol "%content" requires explicit package name at script.pl line 20.

The $content{item} is requesting a value from the hash %content and you never defined/assigned such variable. the $content is an scalar variable not hash variable %content.

{
    #in perl 5.20 you can also
    use 5.020;
    use experimental 'postderef';
    print "key-postderef: $_\n" for keys $content->%*;
}

Now step deeper - to the arrayref - again you can print out the reference type

printf "reftype:%s\n", ref($aref);
#reftype:ARRAY

print all elements of array

print "arr-item: $_\n" for @{$aref};

but again NOT

#print "$_\n" for @aref;
#dies: Global symbol "@aref" requires explicit package name at script.pl line 37.

{
    #in perl 5.20 you can also
    use 5.020;
    use experimental 'postderef';
    print "aref-postderef: $_\n" for $aref->@*;
}

Here is an simple rule:

my @arr;               #array variable
my $arr_ref = \@arr;   #scalar - containing a reference to @arr

@{$arr_ref} is the same as @arr 
 ^^^^^^^^^^ - array reference in curly brackets

If you have an $arrayref - use the @{$array_ref} everywhere you want use the array.

my %hash;              #hash variable
my $hash_ref = \%hash; #scalar - containing a reference to %hash

%{$hash_ref} is the same as %hash
 ^^^^^^^^^^^ - hash reference in curly brackets

If you have an $hash_ref - use the %{$hash_ref} everywhere you want use the hash.

For the whole structure, the following

say $content->{items}->[0];
say $content->{items}[0];
say ${$content}{items}->[0];
say ${$content}{items}[0];
say ${$content->{items}}[0];
say ${${$content}{items}}[0];

prints the same value 1.

like image 142
cajwine Avatar answered Oct 23 '22 04:10

cajwine


$content is a hash reference, so you always need to use an arrow to access its contents. $content{items} would refer to a %content hash, which you don't have. That's where you're getting that "use of uninitialized value" error from.

like image 24
Erin Call Avatar answered Oct 23 '22 04:10

Erin Call