我有一个我正在解码的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;
但我不确定如何通过哈希结构访问它们。
答案 0 :(得分:7)
一旦你了解规则,挖掘一个大的结构就很简单了:
{}
[]
->
。->
)是可选的。所以:
* $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
的hashref,其中包含数组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;
在这里,autovivification通过在数据中创建一堆垃圾来焚烧你,这是程序输出:
$ VAR1 = { 'cat'=> [ 民主基金, 民主基金, 民主基金, 民主基金, 民主基金, {} ] 'horse'=> [ { 'color'=> '棕色' } ] };
现在你可以通过仔细测试你的结构的每一层存在来防止这种事情,但这是一个巨大的痛苦。相反,我更喜欢使用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可以成为一个真正的救星,当你必须对大而不稳定的数据结构进行大量操作时。
答案 1 :(得分:6)
假设您的$listing
是人,您必须取消引用数组和哈希引用。
# 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'
答案 2 :(得分:2)
my @pets = $listing->{pets}->{cats};
这不符合您的想法。 $listing->{pets}->{cats}
包含数组的引用。您的新@pets
数组最终只包含一个元素 - 数组引用。
你真正需要的是
my @pets = @{ $listing->{pets}{cats} };
这会对数组引用进行处理,并为您提供实际的数组。请注意,我还删除了表达式中的可选第二个箭头。
一旦你得到了数组,它的每个元素都是一个哈希引用。
foreach (@pets) {
say $_->{name};
# etc ...
}
当然,您根本不需要中间数组。
foreach (@{ $listing->{pets}{cats} }) {
say $_->{name};
}