0

I am trying to encode a perl nested hash and send it to some web application. Somehow the json encoder converts the numbers or floats to strings. The web application sees the data as strings and can't plot the chart. I can add code in the web application to convert them back to numbers, but I am looking for better solution of not having the numbers as strings in the first place.

Here is the code:

use strict;
use warnings;
use CGI qw/param/;
use JSON::XS;
my $json_obj = JSON::XS->new->allow_nonref;


## Build some Perl data
my %perl_data;

 $perl_data{'numbers'}{'nested'}  = [qw/1 -2 4 2 5 6/] ;
 $perl_data{'mix'}{'AnotherLevel'}  = [qw/null "Temp" 4 2 5 6/] ;
print "Content-type: text/html\n\n"; 
print $json_obj->pretty->encode(\%perl_data);

Here is the output where everything is just stringified:

Content-type: text/html

{
   "numbers" : {
      "nested" : [
         "1",
         "-2",
         "4",
         "2",
         "5",
         "6"
      ]
   },
   "mix" : {
      "AnotherLevel" : [
         "null",
         "\"Temp\"",
         "4",
         "2",
         "5",
         "6"
      ]
   }
}

In the above code, I even tried the following, but to no avail.

use JSON;
my $json_obj = JSON;

Any help is greatly appreciated.

TJ B
  • 157
  • 7

2 Answers2

1

Don't initialize them as strings, and you won't have a problem:

use strict;
use warnings;
use CGI qw/param/;
use JSON::XS;
my $json_obj = JSON::XS->new->allow_nonref;

## Build some Perl data
my %perl_data = (
    'numbers' => {'nested'       => [1, -2, 4, 2, 5, 6]},
    'mix'     => {'AnotherLevel' => [qw/null "Temp"/, 4, 2, 5, 6]},
);

print "Content-type: text/html\n\n"; 
print $json_obj->pretty->encode(\%perl_data);

Outputs:

Content-type: text/html

{
   "numbers" : {
      "nested" : [
         1,
         -2,
         4,
         2,
         5,
         6
      ]
   },
   "mix" : {
      "AnotherLevel" : [
         "null",
         "\"Temp\"",
         4,
         2,
         5,
         6
      ]
   }
}
Miller
  • 34,962
  • 4
  • 39
  • 60
1

The JSON::XS documentation actually has a good section which describes how Perl data structures are serialized as JSON. In particular, it says for scalars:

JSON::XS will encode undefined scalars as JSON null values, scalars that have last 
been used in a string context before encoding as JSON strings, and anything else 
as number values.

When you define your array of numbers using qw, you are using them in a string context. (qw means "quote word" and is generally used to save some typing when defining a list of words.)

Note also that null in JSON is represented by the undef value in Perl. When you say qw/null/, you're just creating the literal string 'null'.

So you have two options.

Define your array like this:

 $perl_data{'numbers'}{'nested'}  = [1, -2, 4, 2, 5, 6] ;
 $perl_data{'mix'}{'AnotherLevel'}  = [undef, "Temp", 4, 2, 5, 6] ;

Or, force-numify all your numbers by adding zero to them before you serialize. E.g.

 $perl_data{'numbers'}{'nested'} = [ map { $_ + 0 } qw/1 -2 4 2 5 6/ ];
friedo
  • 65,762
  • 16
  • 114
  • 184