在 perl 中访问 json 结构的值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8258387/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:04:48  来源:igfitidea点击:

Accessing values of json structure in perl

jsonperlhashhash-of-hashes

提问by bdizzle

I have a json structure that I'm decoding that looks like this:

我有一个正在解码的 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" },
              ],
    },
  },
}

I'm able to print the city, id, nameby doing:

我能打印cityidname这样做:

foreach my $listing ($decoded->{person})
{ 
    my $city = $listing->{city};
    my $name = $listing->{name};
    name - $city - \n";
}

however, I'm unsure of how to print the pets->catsor pets->dogs. I'm able to do a dump of them by:

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

my @pets = $listing->{pets}->{cats};
dump @pets;

but I'm not sure how to access them through the hash structure.

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

回答by dave

Assuming your $listingis a personyou have to dereference array and hash refs.

假设您$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
}

and so on for other stuff.

等等其他东西。

To access them from the structure you can do:

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

say $listing->{pets}->{cats}->[0]->{name}; # this will print 'cat1'

回答by daotoad

Digging into a big structure is pretty simple, once you know the rules:

一旦你知道了规则,挖掘一个大的结构非常简单:

  • Wrap hash keys in {}
  • Wrap array indexes in []
  • If your top level variable is a reference, use ->before the first identifier.
  • After the first set of braces or brackets, additional arrows (->) are optional.
  • 包装散列键 {}
  • 将数组索引包裹在 []
  • 如果您的顶级变量是引用,请->在第一个标识符之前使用。
  • 在第一组大括号或括号之后,附加箭头 ( ->) 是可选的。

So: * $data->{person}{name}returns 'Joe Smith'* $data->{person}->{name}also returns 'Joe Smith'* $data->{pets}{cats}[0]{age}returns 6.

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

For way more detail on this topic, see the Perl Data Structures Cookbook (perldoc perldsc)

有关此主题的更多详细信息,请参阅Perl Data Structures Cookbook (perldoc perldsc)

When you work with big structures like this there are some important things to be aware of. The biggest of these is autovivification. Autoviv means that Perl will automatically make data structure elements pop into existence for you to make your life easier. Unfortunately it can also make things difficult.

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

For example, autoviv is great when I do this:

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

my $data;
$data->{horse}[0]{color} = 'brown';

Autoviv magically turns $datainto a hashref that contains the key horsewith an array ref as its value. The array ref gets populated by a hash ref. The final hash ref then gets the key value pair of color => brown.

Autoviv 神奇地变成$data了一个 hashref,其中包含horse一个以数组 ref 作为其值的键。数组 ref 由散列 ref 填充。最终的哈希引用然后获取 的键值对color => brown

The problem comes in when you are walking a structure and do deep tests for existence:

当你在一个结构中行走并对存在性进行深入测试时,问题就出现了:

# Code from above continues:

if( exists $data->{cat}[5]{color} ) {
    print "Cat 5 has a color\n";
}

use Data::Dumper;
print Dumper $data;

Here, autovivification burns you by creating a bunch of junk in data, here's the program output:

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

$VAR1 = {
      'cat' => [
                 undef,
                 undef,
                 undef,
                 undef,
                 undef,
                 {}
               ],
      'horse' => [
                   {
                     'color' => 'brown'
                   }
                 ]
    };

Now you can guard against this kind of thing by carefully testing each layer of your structure for existence, but it's a huge pain in the butt. Instead, I prefer to use Data::Diver.

现在你可以通过仔细测试你结构的每一层是否存在来防范这种事情,但这是一个巨大的痛苦。相反,我更喜欢使用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;

$datais unchanged here.

$data这里不变。

Also, you may have noticed that since Divetakes a list of keys or indexes, that means its easy to programatically build up a list of keys/indexes and descend an arbitrary path in your code.

此外,您可能已经注意到,由于Dive采用键或索引列表,这意味着很容易以编程方式构建键/索引列表并在代码中沿任意路径下降。

Data::Diver can be a real life saver when you have to do a lot of manipulation of big, wonky data structures.

当您必须对大型、不稳定的数据结构进行大量操作时,Data::Diver 可以成为真正的救星。

回答by Dave Cross

my @pets = $listing->{pets}->{cats};

This isn't doing what you think it is. $listing->{pets}->{cats}contains a referenceto an array. Your new @petsarray ends up contains just one element - the array reference.

这不是你认为的那样。$listing->{pets}->{cats}包含对数组的引用。您的新@pets数组最终只包含一个元素 - 数组引用。

What you actually need is

你真正需要的是

my @pets = @{ $listing->{pets}{cats} };

This deferences the array reference and gets you the actual array. Notice that I've also dropped the optional second arrow in the expression.

这会尊重数组引用并为您提供实际数组。请注意,我还在表达式中删除了可选的第二个箭头。

Once you've got the array, each element of it is a hash reference.

一旦你得到了数组,它的每个元素都是一个散列引用。

foreach (@pets) {
  say $_->{name};
  # etc ...
}

Of course, you don't need the intermediate array at all.

当然,您根本不需要中间数组。

foreach (@{ $listing->{pets}{cats} }) {
  say $_->{name};
}