I have created a script to get some information from various external sources, the results should then be in json
format. There is a lot of data and I push everything to an array in a loop, then print the json
array after everything has been completed, an extract of that loop part of the script:
#!/usr/bin/perl
use JSON -convert_blessed_universally;
use strict;
use warnings;
my @json_arr;
my @servers = ("SERVER1", "SERVER2");
my @details = ("SERVER1,10.1.2.3,Suse Linux",
"SERVER2,10.1.2.4,Windows 10",
"SERVER3,10.1.2.5,Windows XP");
my $json = JSON->new->convert_blessed;
foreach my $server(@servers) {
foreach (@details) {
my @detail = split(',',$_);
if ($server eq $detail[0]) {
push @json_arr, {name => "$server", ip => "$detail[1]", os => "$detail[2]"};
}
}
}
my $result = $json->encode(@json_arr);
print $result;
This gives an output of:
[
{
"name" : "SERVER1",
"ip" : "10.1.2.3",
"os" : "Suse Linux",
},
{
"name" : "SERVER2",
"ip" : "10.1.2.4",
"os" : "Widows 10"
}
]
and a screenshot:
I am however trying to do it by setting a key element instead and having the additional data as children of the device name, i.e:
{
"instance" : [
{
"SERVER1" : {
"ip" : "10.1.2.3",
"os" : "Suse Linux"
},
"SERVER2" : {
"ip" : "10.1.2.4",
"os" : "Windows 10"
}
}
]
}
So I have tried a few things, including something like the below, then pushing to array, but I am getting funny results and just not getting the desired results.
my $json = '{
"instance" : [
$server => {
ip => "$detail[0]",
os => "$detail[1]"
}
]
}';
push @json_arr, $json;
2
Answers
It only takes a small re-arrangement
A few notes
No need for quotes around variables, since they get evaluated anyway (
"$detail[0]"
–>$detail[0]
etc)No need for quotes around hash keys, as a syntax convenience:
key => 'value'
is OK (and if the value is a variable it’s justkey => $var
). That is, as long as there are no spaces in the key nameOne way to pretty-print an existing JSON string:
There may be a question of whether a hashref around each server entry (JSON objects) is needed or not; the above was confirmed in a comment after a discussion so I settled with it.
But if the output only needs a hashref with entries for servers in the array (and not an array of hashrefs for each server) then the code in the question can be modified to
Now this hash has details for all servers, and can be encoded with the key
instance
. Then it is not clear to me what the overall structure should be; one option isThis would be suitable if there is more data in reality. If not then there may not be any need for an arrayref, but encode the usual
The problem is that you are adding hashes to an array (
push @json_arr, ...
) when you mean to add to a hash ($instance{ $server_name } = ...
).Or using
map
:This produces the following, as requested:
(This is different than zdim’s first solution.)
Note that I got rid of the nested loops because they are nasty. For a few items, it’s not a problem. But performance would suffer is
@servers
or@details
would become large. So it’s a bad idea, and a bad habit to get into.Having an array which only even has a single element is weird. Did you perhaps want
This would be achieved by replacing
with