JSON in Perl
JSON (JavaScript Object Notation) is a lightweight data interchange (serialization) format inspired by JavaScript object literal syntax.
examples/sample.json
{ "YAML" : "YAML Ain't Markup Language", "Languages" : [ "perl", "python", "javascript" ] }
JSON implementations in Perl
There are several modules that can convert Perl data structures to JSON, and JSON to Perl data structures.
- JSON
- JSON::PP
- JSON::Syck
- JSON::XS
- Cpanel::JSON::XS
- Mojo::JSON, part of Mojolicious.
- JSON::MaybeXS The recommended!
- JSON::Meth
JSON::PP is a Pure-Perl implementation that can be found in the recent releases of Perl core. According to comments on this article Mojo::JSON, which is also a pure-Perl implementation, is 50% faster than JSON::PP.
According to my measurements Cpanel::JSON::XS is the fastest implementation and despite its name, the only connection to Cpanel is that they sponsor the maintenance of it.
JSON::MaybeXS is a wrapper around a number of these implementations. It will use the XS (and therefore much faster) version if it is installed, and will use the Pure-Perl version if the XS version is not installed.
There are plenty of other modules on CPAN handling JSON in various special cases. If you know about another one you think should be mentioned here, please send a note or a pull-request.
Usage example: Encoding Perl to JSON
Let's say we have a data structure in Perl - a reference of a HASH with an internal array, and internal hash, and one of the keys, 'gender', without a value. Having no value is represented with undef in Perl.
my $student = { name => 'Foo Bar', email => 'foo@bar.com', gender => undef, classes => [ 'Chemistry', 'Math', 'Literature', ], address => { city => 'Fooville', planet => 'Earth', }, };
We can use the encode_json function exported by the Cpanel::JSON::XS module to convert this data structure to a JSON string:
examples/json_encode.pl
use strict; use warnings; use 5.010; use JSON::MaybeXS qw(encode_json decode_json); my $student = { name => 'Foo Bar', email => 'foo@bar.com', gender => undef, classes => [ 'Chemistry', 'Math', 'Litreture', ], address => { city => 'Fooville', planet => 'Earth', }, }; my $student_json = encode_json $student; say $student_json;
The resulting output looks like this:
{"classes":["Chemistry","Math","Literature"],"gender":null,"name":"Foo Bar","email":"foo@bar.com","address":{"city":"Fooville","planet":"Earth"}}
Even without knowing JavaScript, you can see that it is quite similar to what we had in Perl, though this is a compact version of the JSON string and thus there are no linebreaks. Still we can see that instead of the => we used for representing key-value pairs, here we have :, and instead of the undef, here we have null. Oh and the keys are all inside double-quotes.
We can now take this string, save it to file or send it to another computer.
Encoding JSON in a human-readable way
While the above JSON is compact, it is also quite difficult to read and manually edit. We can ask the JSON encoder to make the JSON pretty. (Sometimes this is called JSON beautification or JSON beautifier). The syntax is slightly different:
examples/json_encode_pretty.pl
use strict; use warnings; use 5.010; use JSON::MaybeXS (); my $student = { name => 'Foo Bar', email => 'foo@bar.com', gender => undef, classes => [ 'Chemistry', 'Math', 'Litreture', ], address => { city => 'Fooville', planet => 'Earth', }, }; my $json = JSON::MaybeXS->new(utf8 => 1, pretty => 1, sort_by => 1); my $student_json = $json->encode($student); say $student_json;
(You might need a relatively recent version of Cpanel::JSON::XS to support the sort_by parameter.
$ perl examples/json_encode_pretty.pl
So is the result:
{ "address" : { "city" : "Fooville", "planet" : "Earth" }, "classes" : [ "Chemistry", "Math", "Litreture" ], "email" : "foo@bar.com", "gender" : null, "name" : "Foo Bar" }
Decoding JSON to Perl
In the other way around, let's assume we have a JSON string in the $student_json variable. We can use the decode_json function exported by the Cpanel::JSON::XS module to convert this string to a Perl data structure and then we use Data::Dumper to print out a more familiar representation of the data.
examples/json_decode.pl
use strict; use warnings; use 5.010; use JSON::MaybeXS qw(encode_json decode_json); my $student_json = '{"classes":["Chemistry","Math","Litreture"],"gender":null,"name":"Foo Bar","email":"foo@bar.com","address":{"city":"Fooville","planet":"Earth"}}'; my $student = decode_json $student_json; use Data::Dumper; print Dumper $student;
The output will look like this though of course the order of the keys might be different. After all Perl does not maintain order among the hash keys.
$VAR1 = { 'gender' => undef, 'email' => 'foo@bar.com', 'address' => { 'planet' => 'Earth', 'city' => 'Fooville' }, 'classes' => [ 'Chemistry', 'Math', 'Literature' ], 'name' => 'Foo Bar' };
From these two examples it is quite easy to construct a round-trip example, that encodes a Perl data structure to JSON and then decodes the string back. Of course that's not very interesting in itself. It would be much more interesting to also save the file to the disk in the middle. Further down you'll find an exercise that will do that.
More about JSON
Of course the above was just a taste into how the encoding/decoding works. There are quite a few issues you might need to be aware, probably the most important is how the encoding handles blessed Perl objects.
Exercise
As an exercise, let's create a script that acts as a counter. It will accept a string on the command line, increase a counter and display that value. Each string will have its own counter. It would work like this:
$ count foo foo: 1 $ count foo foo: 2 $ count bar bar: 1 $ count foo foo: 3
Other languages
PHP has built-in functions such as json_decode and json_encode.
Python comes with a class called json that will handle all aspects of JSON processing.
Ruby also comes with a standard library handling JSON files
Comments
I want to parse JSON file without using perl module.. Can you please help..
---
The quick and dirty way is to change the JSON syntax to Perl syntax and then Eval it back into Perl, like this:
my $JSON='json string here'; $JSON=~s/":/"=>/g; my $PERL=eval $JSON;
That will work about 95% of the time.
--- Good thinking! Love it! Works great with json from both openweathermap.org and sunrise-sunset.org.
--- I just bumped into JSON::Parse, which seems to have recent activities, compared to JSON... Does anybody know the motivation to abandon JSON in favor of JSON::Parse?
Here we are taking a static json data in the perl script, right?. What if i have a json file and I need to assign the perl variables with json data.
---
I don't know what do you mean by "static json data", but in any case I think after reading an example and/or the documentation you need to write some code, experiment a bit and then show your code if you have some question about it.
--- Haha, true.
---
Hello Gabor,
I HAVE been writing some perl and experimenting with decoded JSON results. Your decode example above is a good introduction but quite superficial and doesn't help me get to the next level. I have a JSON object that is large, deep and complex: arrays in hashes, hashes in arrays, etc. Dumper shows me that I have a valid JSON object with much data. My task is to filter certain data from the JSON object but I can't seem to get past the first level. Dewang asks the question, "...I need to assign the perl variables with json data..."
I think he means to ask, "How can I assign a part of the JSON object data to a perl variable?" Here is my approach so far: ... open($jsonFile, "<", $ARGV[0]) || die("$ARGV[0] not found...");
# Unset the separator to get the entire file. local $/ = undef; $jsonIn = <$jsonFile>; close($jsonFile);
# Initialize a JSON object $json = JSON->new;
# decode returns a reference; a pointer. $data = $json->decode($jsonIn); #print Dumper($data); # Shows lots of data as expected
# Look at the data object reference as returned from decode print "raw:".$data."\n"; # HASH(0x1899b28) print "ref:".ref($data)."\n"; # HASH print "keys:".keys($data)."\n"; # 4
$, = "\n"; print keys($data); # shows the key names print "\n"; $, = "";
# Look at one of the hashes directly from the data object print "raw:".$data->{SUMMARY}."\n"; # HASH(0x1c8e710) print "ref:".ref($data->{SUMMARY})."\n"; # HASH print "keys:".keys($data->{SUMMARY})."\n"; # 4
$, = "\n"; print keys($data->{SUMMARY}); # shows the key names print "\n"; $, = "";
# Why can't I assign a hash from the data object to a hash variable? my %summary = $data->{SUMMARY}; # no error print "raw:".%summary."\n"; # 1/8 ? print "ref:[".ref(%summary)."]\n"; # [] ? print "keys:".keys(%summary)."\n"; # 1 ? Should be over 700
# end of perl file
---
The question has nothing to do with JSON. These are just Perl data structure operation unrelated to where did the data arrive from.
A reference to a hash and a hash are two different things in perl,
$data->{SUMMARY} is probably a reference to HASH so if you'd like to assign it to a has you need to dereference it:
my %summary = %{ $data->{SUMMARY} };
For the next level you need to learn more about Perl data structures, references and dereferencing.
---
Thanks. As usual, I tried a bunch of ways to dereference it, just not that way. I'll take another look and read up on referencing.
Published on 2015-05-27