在perl中访问json结构的值

bdi*_*zle 4 perl hash json hash-of-hashes

我有一个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" },
              ],
    },
  },
}
Run Code Online (Sandbox Code Playgroud)

我能打印city,id,name这样做:

foreach my $listing ($decoded->{person})
{ 
    my $city = $listing->{city};
    my $name = $listing->{name};
    name - $city - \n";
}
Run Code Online (Sandbox Code Playgroud)

但是,我不确定如何打印pets->catspets->dogs.我可以通过以下方式转储它们:

my @pets = $listing->{pets}->{cats};
dump @pets;
Run Code Online (Sandbox Code Playgroud)

但我不确定如何通过哈希结构访问它们.

dav*_*ave 8

假设你$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
}
Run Code Online (Sandbox Code Playgroud)

等等其他东西.

要从结构中访问它们,您可以执行以下操作:

say $listing->{pets}->{cats}->[0]->{name}; # this will print 'cat1'
Run Code Online (Sandbox Code Playgroud)


dao*_*oad 7

一旦你了解规则,挖掘到一个大的结构是非常简单的:

  • 将哈希密钥包装进去 {}
  • 包装数组索引 []
  • 如果您的顶级变量是引用,请->在第一个标识符之前使用.
  • 在第一组括号或括号之后,额外的箭头(->)是可选的.

所以:*$data->{person}{name}return 'Joe Smith' *$data->{person}->{name}也返回'Joe Smith' *$data->{pets}{cats}[0]{age}返回6.

有关此主题的更多详细信息,请参阅Perl数据结构手册(perldoc perldsc)

当你使用像这样的大型结构时,有一些重要的事情需要注意.其中最大的是autovivification.Autoviv意味着Perl会自动生成数据结构元素,让您的生活更轻松.不幸的是,它也会让事情变得困难.

例如,当我这样做时,autoviv很棒:

my $data;
$data->{horse}[0]{color} = 'brown';
Run Code Online (Sandbox Code Playgroud)

Autoviv神奇地变成$data了一个hashref,它包含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;
Run Code Online (Sandbox Code Playgroud)

在这里,autovivification通过在数据中创建一堆垃圾来焚烧你,这是程序输出:

$ 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;
Run Code Online (Sandbox Code Playgroud)

$data 在这里没有改变.

此外,您可能已经注意到,由于Dive获取了一个键或索引列表,这意味着它易于以编程方式构建键/索引列表并在代码中下降任意路径.

Data :: Diver可以成为一个真正的生命保护程序,当你必须对大而不稳定的数据结构进行大量操作时.