Reputation: 5069
I have a perl code snippet
use JSON::XS;
$a = {"john" => "123", "mary" => "456"};
print encode_json($a),"\n";
The output is
{"john":"123","mary":"456"}
Wonder if there is an option to cause encode_json function (from JSON::XS module) to encode it so that the values (123, 456) are not surrounded by double-quote. i.e., like
{"john":123,"mary":456}
Unfortunately I can't change the hash in $a because it's passed to me from another function. Wonder if there is any trick on encode_json().
Thanks!
Upvotes: 2
Views: 1327
Reputation: 4883
You probably need to preprocess the data yourself, prior to JSON serialization.
This solution uses Data::Leaf::Walker to traverse an arbitrary structure, converting strings to numbers.
use JSON;
use Data::Leaf::Walker;
use Scalar::Util qw();
my $a = {"john" => "123",
"mary" => ["456","aa"],
"fred" => "bb",
"nested" => {"Q" => undef, "A" => 42},
};
my $walker = Data::Leaf::Walker->new( $a );
while (my ( $key_path, $value ) = $walker->each ) {
$walker->store($key_path, $value + 0)
if Scalar::Util::looks_like_number $value;
};
print to_json($a);
Output: {"john":123,"nested":{"A":42,"Q":null},"mary":[456,"aa"],"fred":"bb"}
Upvotes: 6
Reputation: 3837
You shouldn't use JSON::XS
directly, just JSON
will already load JSON::XS
if available.
A scalar in Perl is tagged whether it is a string or a number, and here you're providing strings. Remove the quotes from your numbers, and they should show up unquoted as JSON
already does that automatically.
If you're reading strings (from say a database) then you can coerce the strings to numbers like this:
{ john => 0+$john, mary => 0+$mary }
Update, here's a recursive replacement:
#!/usr/bin/env perl
use JSON;
use Modern::Perl;
use Scalar::Util qw( looks_like_number );
my $structure = {
john => "123",
mary => 456,
deeper => {
lucy => "35zz",
names => [
"john",
"123",
456,
],
},
};
sub make_numbers_recursively {
my ( $data ) = shift;
if ( ref $data eq 'HASH' ) {
# Replace hash values with recurisvely updated values
map { $data->{ $_ } = make_numbers_recursively( $data->{ $_ } ) } keys %$data;
} elsif ( ref $data eq 'ARRAY' ) {
# Replace each array value with recursively processed result
map { $_ = make_numbers_recursively( $_ ) } @$data;
} else {
$data += 0 if looks_like_number( $data );
}
return $data;
}
my $json = JSON->new->pretty;
say $json->encode( $structure );
make_numbers_recursively( $structure );
say $json->encode( $structure );
This outputs:
{
"mary" : 456,
"deeper" : {
"names" : [
"john",
"123",
456
],
"lucy" : "35zz"
},
"john" : "123"
}
{
"mary" : 456,
"deeper" : {
"names" : [
"john",
123,
456
],
"lucy" : "35zz"
},
"john" : 123
}
Beware that it modifies the structure in-place, so if you need the original data for anything you might want to Clone
or Data::Clone
it first.
Upvotes: 2