Perl hash to json conversion? - json

i have coded a crawler in perl to to get the url, title of the site and put it into a hash as following
$VAR1 = {
'address1' => {
'url' => 'dthree',
'title' => 'done'
},
'address2' => {
'url' => 'dthree',
'title' => 'done'
}
};
then how can i convert it into json format .. im using MOJO::Json

The first four lines in Mojo::JSON's SYNOPSIS will tell you.
use Mojo::JSON;
my $json = Mojo::JSON->new->encode( $VAR1 );

Related

How to access data on Perl Object structures

I have the following perl code in where I have a perl structure as follows:
`
use Data::Dumper;
my %data = (
'status' => 200,
'message' => '',
'response' => {
'name' => 'John Smith',
'id' => '1abc579',
'ibge' => '3304557',
'uf' => 'XY',
'status' => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' )
}
);
my $resp = $data{'status'};
print "Response is $resp \n";
print Dumper(%data->{'response'});
Getting the status field works, however If I try something like this:
my $resp = $data{'response'}
I get Response is HASH(0x8b6640)
So I'm wondering if there's a way I can extract all the data of the 'response' field on the same way I can do it for 'status' without getting that HASH...
I've tried all sort of combinations when accessing the data, however I'm still getting the HASH back when I try to get the content of 'response'
$data{'response'} is the correct way to access that field on a hash called %data. It's returning a hash reference, which prints out by default in the (relatively unhelpful) HASH(0x8b6640) syntax you've seen. But if you pass that reference to Dumper, it'll show you everything.
print Dumper($data{'response'});
to actually access those subfields, you need to dereference, which is done with an indirection -> operation.
print $data{'response'}->{'name'}
The first access doesn't need the -> because you're accessing a field on a hash variable (i.e. a variable with the % sigil). The second one does because you're dereferencing a reference, which, at least in spirit, has the $ sigil like other scalars.
Thanks for your posts. I fixed the code as follows:
use Data::Dumper;
my %data = (
'status' => 200,
'message' => '',
'response' => {
'name' => 'John Smith',
'id' => '1abc579',
'ibge' => '3304557',
'uf' => 'XY',
'status' => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' )
}
);
my $resp = $data{'response'};
print Dumper($resp);
Now it works like a charm, and I'm able to get the data I want.

Creating hash of hashes from list of network interface config files in perl

I'm trying to load the list of network interface configuration files on Linux into the hash of hashes and further encode them into JSON. This is the code that I'm using:
#!/usr/bin/env perl
use strict;
use diagnostics;
use JSON;
use Data::Dumper qw(Dumper);
opendir (DIR, "/etc/sysconfig/network-scripts/");
my #configs =grep(/^ifcfg-*/, readdir(DIR));
my $output = "metadata/json_no_comment";
my %configuration;
my $key;
my $value;
my %temp_hash;
foreach my $input ( #configs) {
$input= "/var/tmp/rhel6.8/" . $input;
open (my $JH, '<', $input) or die "Cannot open the input file $!\n";
while (<$JH>) {
s/#.*$//g;
next if /^\s*#/;
next if /^$/;
for my $field (split ) {
($key, $value) = split /\s*=\s*/, $field;
$temp_hash{$key} = $value;
}
$configuration{$input} = \%temp_hash;
}
close $JH;
}
print "-----------------------\n";
print Dumper \%configuration;
print "-----------------------\n";
my $json = encode_json \%configuration;
open (my $JNH, '>', $output) or die "Cannot open the output file $!\n";
print $JNH $json;
close $JNH;
The data structure, that I'm getting is following:
$VAR1 = {
'/etc/sysconfig/network-scripts/ifcfg-lo' => {
'BOOTPROTO' => 'dhcp',
'NAME' => 'loopback',
'TYPE' => 'Ethernet',
'IPV6INIT' => 'yes',
'HWADDR' => '"52:54:00:65:e7:8c"',
'DEVICE' => 'lo',
'NETBOOT' => 'yes',
'NETMASK' => '255.0.0.0',
'BROADCAST' => '127.255.255.255',
'IPADDR' => '127.0.0.1',
'NETWORK' => '127.0.0.0',
'ONBOOT' => 'yes'
},
'/etc/sysconfig/network-scripts/ifcfg-eth0' => $VAR1->{'/etc/sysconfig/network-scripts/ifcfg-lo'}
};
The data structure, I'm looking for is the following:
$VAR1 = {
'/etc/sysconfig/network-scripts/ifcfg-lo' => {
'BOOTPROTO' => 'dhcp',
'NAME' => 'loopback',
'TYPE' => 'Ethernet',
'IPV6INIT' => 'yes',
'HWADDR' => '"52:54:00:65:e7:8c"',
'DEVICE' => 'lo',
'NETBOOT' => 'yes',
'NETMASK' => '255.0.0.0',
'BROADCAST' => '127.255.255.255',
'IPADDR' => '127.0.0.1',
'NETWORK' => '127.0.0.0',
'ONBOOT' => 'yes'
},
'/etc/sysconfig/network-scripts/ifcfg-eth0' => {
'BOOTPROTO' => 'dhcp',
'NAME' => '"eth0"',
'TYPE' => 'Ethernet',
'IPV6INIT' => 'yes',
'HWADDR' => '"52:54:00:65:e7:8c"',
'NETBOOT' => 'yes',
'ONBOOT' => 'yes'
}
};
Any idea what am I doing wrong? Why the first nested hash is created correctly and the second one is not? I suspect, that it has something to do with reading the files line by line, but I have to do it, because I need to filter out the commented lines before JSON conversion.
Thanks for any help.
Edit: I have modified the script as suggested by Borodin and it works. Thanks!
The problem is that $configuration{$input} always refers to the same hash %temp_hash because you have declared it at file level. You need to created a new hash for each config file by declaring %temp_hash inside the for loop
Also note that next if /^\s*#/ can have no effect because you just deleted any hashes in the line. Your sanitisation should look like
s/#.*//;
next unless /\S/;

from_json and decode_json in perl not working as expected

I am having a json like below.
$response = {"entries":[{"content":{"eStatus":0,"id":"0","enabled":false,"isOK":false,}}]}
$responseContent = from_json($response);
when i am using from_json or decode_json within my perl code I get following as the converted json.
'content' => {
'id' => '0',
'esrsVeAddress' => '',
'isOK' => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' ),
'enabled' => $VAR1->{'entries'}[0]{'content'}{'isOK'},
'eStatus' => 0
}
When value of element is not boolean ( true/false ) conversion happens properly but when its boolean then output is corrupted.
If you will see value of element 'enabled' and 'isOK' both are wrong.
Am i using wrong function 'from_json' or 'decode_json' here.
Any suggestions or guidance is appreciated.
This is the way i am trying to use value of element isOK and enabled.
if ( $isOK = $responseContent->{'entries'}[0]->{'content'}-> {'isOK'} eq "1" ) {
c4lx_log "value is found to be true and so do some business logic";
}
else {
c4lx_log "value is found to be false and so dont do anything here";
}
NOTE:
Input to fucntion 'from_json' or 'decode_json' is coming from the REST response in format as shown above. I have verified that input is passed correctly and as expected. Its just the conversion that is issue here.
If you will see value of element 'enabled' and 'isOK' both are wrong.
No, they are correct. Both ->{enabled} and ->{isOK} are false as in the JSON.
How can i avoid conversion like above
You are actually asking why the module doesn't convert the value (to a string or number). That would cause information to be lost. For example, if the conversion you desire would be performed, encode_json(decode_json($json)) would change the data.
What can be done here to make the value as I am expecting [which is] 'content' => { 'id' => '0', 'esrsVeAddress' => '', 'isOK' => false, 'enabled' => false, 'eStatus' => 0 }
That's impossible using Data::Dumper. Data::Dumper produces valid Perl code, and that's not valid Perl code. However, you can get close to that by using
print(Data::Dumper->Dump(
[ JSON::false, JSON::true, $responseContent ],
[qw( $false $true $responseContent )]));
It produces the following output:
$false = bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' );
$true = bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' );
$responseContent = {
'entries' => [
{
'content' => {
'id' => '0',
'eStatus' => 0,
'enabled' => $false,
'isOK' => $false
}
}
]
};
This is the way i am trying to use value of element isOK and enabled.
It's wrong to expect a boolean to have a specific value. Change
my $isOK;
if ($isOK = $responseContent->{'entries'}[0]->{'content'}->{'isOK'} eq "1")
to
if ($responseContent->{'entries'}[0]->{'content'}->{'isOK'})
That can be simplified to
if ($responseContent->{entries}[0]{content}{isOK})
If you want to store the result for later, use
my $isOK = $responseContent->{entries}[0]{content}{isOK};
if ($isOK)

JSON Data output

Below is the Perl code having JSON data:
use Data::Dumper;
use JSON;
my $var = '{
"episode1": {
"title":"Cartman Gets an Anal Probe",
"id":"103511",
"airdate":"08.13.97",
"episodenumber":"101",
"available":"true",
"when":"08.13.97"
}
},
{
"episode2": {
"title":"Weight Gain 4000",
"id":"103516",
"airdate":"08.20.97",
"episodenumber":"102",
"available":"true",
"when":"08.20.97"
}
}';
my $resp = JSON::jsonToObj( $var );
print Dumper ($resp);
The output is:
$VAR1 = {
'episode1' => {
'when' => '08.13.97',
'episodenumber' => '101',
'airdate' => '08.13.97',
'title' => 'Cartman Gets an Anal Probe',
'id' => '103511',
'available' => 'true'
}
};
I am dumping a JSON data but only episode1 is dumped in the output. But, I want both episode1 and episode2 to be displayed when I dump. How to do it?
Write valid JSON.
From JSON Lint
Parse error on line 14:
...: "08.13.97" }},{ "episode2":
---------------------^
Expecting 'EOF'
If you want an array of objects, you need an array in the data: [...].

Converting perl Data Dumper Format into JSON

I have Dumper outputting data correctly:
'Apps' => [
\{
'name' => '1'
},
\{
'name' => '2'
},
\{
'name' => '3'
},
\{
'name' => '4'
},
\{
'name' => '5'
},
\{
'name' => '6'
},
\{
'name' => '7'
}
],
'code' => 'SUCCESS'
};
But when I convert it to JSON I have a lot of problems:
my #jsonapps;
my #apps = map { $_ } keys %glob;
my %hash;
$hash{'code'} = 'SUCCESS';
for (#apps) {
my $app = { 'name' => $_ };
push (#jsonapps, \$app);
}
# $hash{'Apps'} = \#jsonapps;
my $jsonfinal = encode_json \%hash;
print $jsonfinal;
It definitely has to do when with I try to add an array of hashes in:
$hash{'Apps'} = \#jsonapps;
But I'm having a problem doing that since all the hashes have the same key "name". I need my output to look like:
{"code":"SUCCESS","Apps":[{"name":"1"},{"name":"2"},{"name":"3"},{"name":"4"},{"name":"5"},{"name":"6"},{"name":"7"}]}
Thanks, I appreciate the help - I've scoured everywhere to figure out how to do this, and I'm just banging my head against the wall now. Thanks!
Notice the extra \ in your dump output.
'Apps' => [
\{
'name' => '1'
},
This is because it they are references to hash references. The problem code is here:
for (#apps) {
my $app = { 'name' => $_ };
push (#jsonapps, \$app);
}
$app is already a hashref since you use braces and assign it to a scalar. But adding the \ in front when you push it to #jsonapps means you are pushing the reference to the hashref. You don't need to make it a reference because it is already a reference. You just need to omit the \.
for (#apps) {
my $app = { 'name' => $_ };
push (#jsonapps, $app);
}