我正在解码的json结构看起来像这样:
person => {
city => "Chicago",
id => 123,
name => "Joe Smith",
pets => {
cats => [
{ age => 6, name => "cat1", type => "siamese", weight => "10 kilos" },
{ age => 10, name => "cat2", type => "siamese", weight => "13 kilos" },
],
dogs => [
{ age => 7, name => "dog1", type => "siamese", weight => "20 kilos" },
{ age => 5, name => "dog2", type => "siamese", weight => "15 kilos" },
],
},
},
}
我可以通过执行以下操作来打印city
,id
,name
:
foreach my $listing ($decoded->{person})
{
my $city = $listing->{city};
my $name = $listing->{name};
name - $city - \n";
}
但是,我不确定如何打印pets->cats
或pets->dogs
。我可以通过以下方式转储它们:
my @pets = $listing->{pets}->{cats};
dump @pets;
但是我不确定如何通过哈希结构访问它们。
假设您的$listing
是person,则必须取消引用数组和哈希引用。
# as long as we are assuming $listing is a person
# this goes inside the foreach you posted in your
# question.
# this will print all cats' names
foreach my $cat ( @{ $listing->{pets}->{cats} } )
{
# here $cat is a hash reference
say $cat->{name}; # cat's name
}
以此类推,其他内容。
要从结构中访问它们,您可以做:
say $listing->{pets}->{cats}->[0]->{name}; # this will print 'cat1'
一旦知道规则,挖掘大结构就非常简单:
{}
中包装哈希键[]
中包装数组索引->
。->
)是可选的。所以:* $data->{person}{name}
返回'Joe Smith'
* $data->{person}->{name}
也返回'Joe Smith'
* $data->{pets}{cats}[0]{age}
返回6
。
有关此主题的更多详细信息,请参见Perl Data Structures Cookbook (perldoc perldsc)
当您使用这种大型结构时,需要注意一些重要的事情。其中最大的是autovivification
。 Autoviv意味着Perl将自动使数据结构元素变为现实,以使您的生活更轻松。不幸的是,这也会使事情变得困难。
例如,当我这样做时,autoviv很棒:
my $data;
$data->{horse}[0]{color} = 'brown';
[Autoviv神奇地将$data
转换为包含键horse
且其值为数组ref的哈希引用”。数组引用由哈希引用填充。然后,最终的哈希引用将获得color => brown
的键值对。
当您在建筑物上行走并进行深度测试时会出现问题:
# Code from above continues:
if( exists $data->{cat}[5]{color} ) {
print "Cat 5 has a color\n";
}
use Data::Dumper;
print Dumper $data;
这里,自动生存通过在数据中创建一堆垃圾来烧死您,这是程序输出:
$VAR1 = {
'cat' => [
undef,
undef,
undef,
undef,
undef,
{}
],
'horse' => [
{
'color' => 'brown'
}
]
};
现在,您可以通过仔细测试结构的每一层是否存在来防范这种情况,但这是一个极大的痛苦。相反,我更喜欢使用Data::Diver。
use Data::Diver qw( Dive );
my $dog_20_color = Dive( $data, 'dog', 20, 'color' );
print "Dog 20 is $dog_20_color\n" if defined $dog_20_color;
[$data
在这里不变。
[此外,您可能已经注意到,由于Dive
采用键或索引的列表,这意味着可以轻松地以编程方式建立键/索引的列表并在代码中找到任意路径。
Data :: Diver在必须对大型,笨拙的数据结构进行大量处理的情况下可以成为现实的救星。
my @pets = $listing->{pets}->{cats};
这不是您想的那样。 $listing->{pets}->{cats}
包含数组的reference。您的新@pets
数组最终只包含一个元素-数组引用。
您实际需要的是
my @pets = @{ $listing->{pets}{cats} };
这将引用数组引用,并为您提供实际的数组。请注意,我还在表达式中放置了可选的第二个箭头。
一旦有了数组,它的每个元素都是一个哈希引用。
foreach (@pets) {
say $_->{name};
# etc ...
}
当然,您根本不需要中间数组。
foreach (@{ $listing->{pets}{cats} }) {
say $_->{name};
}