[英]Perl JSON arrays within a parent key
我創建了一個腳本來從各種外部來源獲取一些信息,結果應該是json
格式。 有很多數據,我循環將所有內容推送到一個數組,然后在所有內容完成后打印json
數組,腳本的循環部分的摘錄:
#!/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;
這給出了 output 的:
[
{
"name" : "SERVER1",
"ip" : "10.1.2.3",
"os" : "Suse Linux",
},
{
"name" : "SERVER2",
"ip" : "10.1.2.4",
"os" : "Widows 10"
}
]
和截圖:
然而,我試圖通過設置一個關鍵元素並將附加數據作為設備名稱的子元素來做到這一點,即:
{
"instance" : [
{
"SERVER1" : {
"ip" : "10.1.2.3",
"os" : "Suse Linux"
},
"SERVER2" : {
"ip" : "10.1.2.4",
"os" : "Windows 10"
}
}
]
}
所以我嘗試了一些東西,包括下面的東西,然后推送到數組,但我得到了有趣的結果,只是沒有得到想要的結果。
my $json = '{
"instance" : [
$server => {
ip => "$detail[0]",
os => "$detail[1]"
}
]
}';
push @json_arr, $json;
只需要一個小的重新安排
use warnings;
use strict;
use feature 'say';
use Data::Dumper;
use JSON::XS;
...
my @json_ary;
foreach my $server (@servers) {
foreach (@details) {
my @detail = split /,/;
if ($server eq $detail[0]) {
#push @json_ary, {name => "$server", ip => "$detail[1]" ...
push @json_ary,
{ $server => { ip => $detail[1], os => $detail[2] } }
}
}
}
print Dumper \@json_ary;
# Encode `{ instance => \@json_ary }` for the desired output
my $json = JSON->new->convert_blessed;
my $result = $json->pretty->encode( { instance => \@json_ary } );
say $result;
一些注意事項
不需要在變量周圍加上引號,因為它們無論如何都會被評估( "$detail[0]"
--> $detail[0]
等)
不需要在 hash 鍵周圍加引號,因為語法方便: key => 'value'
可以(如果值是一個變量,它只是key => $var
)。 也就是說,只要鍵名中沒有空格。
一種漂亮打印現有 JSON 字符串的方法:
print JSON::XS->new->ascii->pretty->encode(decode_json $json_str);
可能存在是否需要圍繞每個服務器條目(JSON 對象)的哈希引用的問題; 以上內容在討論后的評論中得到確認,所以我同意了。
但是如果 output 只需要一個 hashref 數組中的服務器條目(而不是每個服務器的 hashrefs 數組)那么問題中的代碼可以修改為
my %server_details;
foreach my $server (@servers) {
foreach (@details) {
my @detail = split /,/;
if ($server eq $detail[0]) {
$server_details{$server} = { ip => $detail[1], os => $detail[2] }
}
}
}
現在這個 hash 擁有所有服務器的詳細信息,並且可以使用密鑰instance
進行編碼。 那么我不清楚整體結構應該是什么; 一種選擇是:
my $result = JSON->pretty->encode( { instance => [ \%server_details ] } );
問題是當您要添加到 hash ( $instance{ $server_name } =...
) 時,您正在將哈希添加到數組 ( push @json_arr, ...
)。
my %servers = map { $_ => 1 } @servers;
my %instance;
for ( @details ) {
my ( $name, $ip, $os ) = split /,/;
next if !$servers{ $name };
$instance{ $name } = {
ip => $ip,
os => $os,
};
}
my @instances = \%instance;
my $data = { instance => \@instances };
或者使用map
:
my %servers = map { $_ => 1 } @servers;
my %instance = (
map { $_->[0] => { ip => $_->[1], os => $_->[2] } }
grep $servers{ $_->[0] },
map [ split /,/ ],
@details
);
my @instances = \%instance;
my $data = { instance => \@instances };
這會根據要求產生以下內容:
{
"instance" : [
{
"SERVER1" : {
"ip" : "10.1.2.3",
"os" : "Suse Linux"
},
"SERVER2" : {
"ip" : "10.1.2.4",
"os" : "Windows 10"
}
}
]
}
(這與 zdim 的第一個解決方案不同。)
請注意,我擺脫了嵌套循環,因為它們很討厭。 對於一些項目,這不是問題。 但是性能會受到影響,因為@servers
或@details
會變大。 所以這是一個壞主意,也是一個壞習慣。
擁有一個甚至只有一個元素的數組很奇怪。 你也許想要
{
"instance" : {
"SERVER1" : {
"ip" : "10.1.2.3",
"os" : "Suse Linux"
},
"SERVER2" : {
"ip" : "10.1.2.4",
"os" : "Windows 10"
}
}
}
這將通過替換來實現
my $data = { instance => \@instances };
和
my $data = { instance => \%instance };
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.