在Perl中解码和使用JSON数据

时间:2022-10-17 10:36:50

I am confused about accessing the contents of some JSON data that I have decoded. Here is an example

我很困惑访问我已解码的一些JSON数据的内容。这是一个例子

I don't understand why this solution works and my own does not. My questions are rephrased below

我不明白为什么这个解决方案有效,而我自己没有。我的问题在下面重述

my $json_raw = getJSON(); 
my $content  = decode_json($json_raw);
print Data::Dumper($content);

At this point my JSON data has been transformed into this

此时我的JSON数据已经转化为此

$VAR1 = { 'items' => [ 1, 2, 3, 4 ] };

My guess tells me that, once decoded, the object will be a hash with one element that has the key items and an array reference as the value.

我的猜测告诉我,一旦解码,该对象将是一个散列,其中一个元素具有关键项和数组引用作为值。

$content{'items'}[0]

where $content{'items'} would obtain the array reference, and the outer $...[0] would access the first element in the array and interpret it as a scalar. However this does not work. I get an error message use of uninitialized value [...]

其中$ content {'items'}将获得数组引用,而外部$ ... [0]将访问数组中的第一个元素并将其解释为标量。但是这不起作用。我收到一条使用未初始化值的错误消息[...]

However, the following does work:

但是,以下工作正常:

$content->{items}[0]

where $content->{items} yields the array reference and [0] accesses the first element of that array.

其中$ content - > {items}产生数组引用,[0]访问该数组的第一个元素。

Questions

  • Why does $content{'items'} not return an array reference? I even tried @{content{'items'}}, thinking that, once I got the value from content{'items'}, it would need to be interpreted as an array. But still, I receive the uninitialized array reference.

    为什么$ content {'items'}不返回数组引用?我甚至试过@ {content {'items'}},认为一旦我从内容{'items'}获得了值,就需要将其解释为数组。但是,我仍然收到未初始化的数组引用。

  • How can I access the array reference without using the arrow operator?

    如何在不使用箭头运算符的情况下访问数组引用?

4 个解决方案

#1


5  

Beginner's answer to beginner :) Sure not as profesional as should be, but maybe helps you.

初学者对初学者的回答:)当然不是应该如此专业,但也许可以帮到你。

use strict;    #use this all times
use warnings;  #this too - helps a lot!
use JSON;

my $json_str = '    { "items" : [ 1, 2, 3, 4 ] }    ';
my $content = decode_json($json_str);

You wrote:

My guess tells me that, once decoded, the object will be a hash with one element that has the key items and an array reference as the value.

我的猜测告诉我,一旦解码,该对象将是一个散列,其中一个元素具有关键项和数组引用作为值。

Yes, it is a hash, but the the decode_json returns a reference, in this case, the reference to hash. (from the docs)

是的,它是一个散列,但是decode_json返回一个引用,在本例中是对hash的引用。 (来自文档)

expects an UTF-8 (binary) string and tries to parse that as an UTF-8 encoded JSON text, returning the resulting reference.

期望UTF-8(二进制)字符串并尝试将其解析为UTF-8编码的JSON文本,并返回结果引用。

In the line

在线

my $content = decode_json($json_str);

you assigning to an SCALAR variable (not to hash).

您分配给SCALAR变量(不是哈希)。

Because you know: it is a reference, you can do the next:

因为你知道:它是一个参考,你可以做下一个:

printf "reftype:%s\n", ref($content);
#print: reftype:HASH       ^   
           #therefore the  +------- is a SCALAR value containing a reference to hash

It is a hashref - you can dump all keys

它是一个hashref - 你可以转储所有密钥

print "key: $_\n" for keys %{$content}; #or in short %$content
#prints: key: items

also you can assing the value of the "items" (arrayref) to an scalar variable

你也可以将“items”(arrayref)的值赋予标量变量

my $aref = $content->{items};   #$hashref->{key}
#or
#my $aref = ${$content}{items}; #$hash{key}

but NOT

#my $aref = $content{items};    #throws error if "use strict;"
#Global symbol "%content" requires explicit package name at script.pl line 20.

The $content{item} is requesting a value from the hash %content and you never defined/assigned such variable. the $content is an scalar variable not hash variable %content.

$ content {item}正在请求散列%内容中的值,并且您从未定义/分配此类变量。 $ content是标量变量而非散列变量%content。

{
    #in perl 5.20 you can also
    use 5.020;
    use experimental 'postderef';
    print "key-postderef: $_\n" for keys $content->%*;
}

Now step deeper - to the arrayref - again you can print out the reference type

现在再深入 - 到arrayref - 再次打印出引用类型

printf "reftype:%s\n", ref($aref);
#reftype:ARRAY

print all elements of array

打印数组的所有元素

print "arr-item: $_\n" for @{$aref};

but again NOT

但同样不是

#print "$_\n" for @aref;
#dies: Global symbol "@aref" requires explicit package name at script.pl line 37.

{
    #in perl 5.20 you can also
    use 5.020;
    use experimental 'postderef';
    print "aref-postderef: $_\n" for $aref->@*;
}

Here is an simple rule:

这是一个简单的规则:

my @arr;               #array variable
my $arr_ref = \@arr;   #scalar - containing a reference to @arr

@{$arr_ref} is the same as @arr 
 ^^^^^^^^^^ - array reference in curly brackets

If you have an $arrayref - use the @{$array_ref} everywhere you want use the array.

如果您有$ arrayref - 请在任何地方使用@ {$ array_ref}来使用数组。

my %hash;              #hash variable
my $hash_ref = \%hash; #scalar - containing a reference to %hash

%{$hash_ref} is the same as %hash
 ^^^^^^^^^^^ - hash reference in curly brackets

If you have an $hash_ref - use the %{$hash_ref} everywhere you want use the hash.

如果你有$ hash_ref - 在你想要的任何地方使用%{$ hash_ref}来使用哈希。

For the whole structure, the following

对于整个结构,如下

say $content->{items}->[0];
say $content->{items}[0];
say ${$content}{items}->[0];
say ${$content}{items}[0];
say ${$content->{items}}[0];
say ${${$content}{items}}[0];

prints the same value 1.

打印相同的值1。

#2


4  

$content is a hash reference, so you always need to use an arrow to access its contents. $content{items} would refer to a %content hash, which you don't have. That's where you're getting that "use of uninitialized value" error from.

$ content是哈希引用,因此您始终需要使用箭头来访问其内容。 $ content {items}将引用您没有的%内容哈希。这就是你从“使用未初始化的值”错误的地方。

#3


0  

I actually asked a similar question here

我其实在这里问了一个类似的问题

The answer:

In Perl, a function can only really return a scalar or a list.

在Perl中,函数只能真正返回标量或列表。

Since hashes can be initialized or assigned from lists (e.g. %foo = (a => 1, b => 2)), I guess you're asking why json_decode returns something like { a => 1, b => 2 } (a reference to an anonymous hash) rather than (a => 1, b => 2) (a list that can be copied into a hash).

由于哈希可以从列表初始化或分配(例如%foo =(a => 1,b => 2)),我想你问为什么json_decode返回类似{a => 1,b => 2}的东西(引用匿名哈希)而不是(a => 1,b => 2)(可以复制到哈希中的列表)。

I can think of a few good reasons for this:

我可以想到几个很好的理由:

in Perl, an array or hash always contains scalars. So in something like { "a": { "b": 3 } }, the { "b": 3 } part has to be a scalar; and for consistency, it makes sense for the whole thing to be a scalar in the same way.

在Perl中,数组或散列总是包含标量。所以像{“a”:{“b”:3}}之类的东西,{“b”:3}部分必须是标量;为了保持一致性,整个事物以同样的方式成为标量是有道理的。

if the hash is quite large (many keys at top-level), it's pointless and expensive to iterate over all the elements to convert it into a list, and then build a new hash from that list. in JSON, the top-level element can be either an object (= Perl hash) or an array (= Perl array). If json_decode returned a list in the former case, it's not clear what it would return in the latter case. After decoding the JSON string, how could you examine the result to know what to do with it? (And it wouldn't be safe to write %foo = json_decode(...) unless you already knew that you had a hash.) So json_decode's behavior works better for any general-purpose library code that has to use it without already knowing very much about the data it's working with.

如果散列非常大(*的许多键),迭代所有元素以将其转换为列表,然后从该列表构建新的散列是毫无意义和昂贵的。在JSON中,*元素可以是对象(= Perl哈希)或数组(= Perl数组)。如果json_decode在前一种情况下返回一个列表,则不清楚在后一种情况下它会返回什么。解码JSON字符串后,您如何检查结果以了解如何处理它? (并且编写%foo = json_decode(...)是不安全的,除非你已经知道你有一个哈希。)所以json_decode的行为对任何必须使用它而不必知道的通用库代码更有效。非常关心它正在使用的数据。

I have to wonder exactly what you passed as an array to json_decode, because my results differ from yours.

我不得不想知道你作为数组传递给json_decode的确切内容,因为我的结果与你的不同。

#!/usr/bin/perl

use JSON qw (decode_json);
use Data::Dumper;
my $json = '["1", "2", "3", "4"]';

my $fromJSON = decode_json($json);

print Dumper($fromJSON);

The result is $VAR1 = [ '1', '2', '3', '4' ];

结果是$ VAR1 = ['1','2','3','4'];

Which is an array ref, where your result is a hash ref

哪个是数组引用,其结果是哈希引用

So did you pass in a hash with element items which was a reference to an array?

那么你是否传递了一个带有元素项的哈希值,这是一个对数组的引用?

In my example you would get the array by doing

在我的例子中,你将通过这样做获得数组

my @array = @{ $fromJSON };

In yours

my @array = @{ $content->{'items'} }

#4


0  

I don't understand why you dislike the arrow operator so much!

我不明白为什么你这么不喜欢箭头操作员!

The decode_json function from the JSON module will always return a data reference.

JSON模块中的decode_json函数将始终返回数据引用。

Suppose you have a Perl program like this

假设您有这样的Perl程序

use strict;
use warnings;

use JSON;

my $json_data = '{ "items": [ 1, 2, 3, 4 ] }';

my $content = decode_json($json_data);

use Data::Dump;
dd $content;

which outputs this text

输出此文本

{ items => [1 .. 4] }

showing that $content is a hash reference. Then you can access the array reference, as you found, with

显示$ content是哈希引用。然后,您可以访问数组引用,如您所见

dd $content->{items};

which shows

[1 .. 4]

and you can print the first element of the array by writing

你可以通过写作打印数组的第一个元素

print $content->{items}[0], "\n";

which, again as you have found, shows just

再次,正如你所发现的,只显示

1

which is the first element of the array.

这是数组的第一个元素。

As @cjm mentions in a comment, it is imperative that you use strict and use warnings at the start of every Perl program. If you had those in place in the program where you tried to access $content{items}, your program would have failed to compile, and you would have seen the message

正如@cjm在评论中提到的那样,必须在每个Perl程序的开头使用严格和使用警告。如果你在试图访问$ content {items}的程序中有那些,你的程序将无法编译,你会看到这条消息

Global symbol "%content" requires explicit package name

which is a (poorly-phrased) way of telling you that there is no %content so there can be no items element.

这是一种(措辞不当)告诉你没有%内容的方式,所以没有item元素。

The scalar variable $content is completely independent from the hash variable %content, which you are trying to access when you write $content{items}. %content has never been mentioned before and it is empty, so there is no items element. If you had tried @{$content->{items}} then it would have worked, as would @{${$content}{items}}

标量变量$ content完全独立于您在编写$ content {items}时尝试访问的哈希变量%content。之前从未提及%content,它是空的,因此没有items元素。如果您尝试了@ {$ content - > {items}},那么它就会起作用,就像@ {$ {$ content} {items}}一样

If you really have a problem with the arrow operator, then you could write

如果你对箭头操作符确实有问题,那么你可以写

print ${$content}{items}[0], "\n";

which produces the same output; but I don't understand what is wrong with the original version.

产生相同的输出;但我不明白原版本有什么问题。

#1


5  

Beginner's answer to beginner :) Sure not as profesional as should be, but maybe helps you.

初学者对初学者的回答:)当然不是应该如此专业,但也许可以帮到你。

use strict;    #use this all times
use warnings;  #this too - helps a lot!
use JSON;

my $json_str = '    { "items" : [ 1, 2, 3, 4 ] }    ';
my $content = decode_json($json_str);

You wrote:

My guess tells me that, once decoded, the object will be a hash with one element that has the key items and an array reference as the value.

我的猜测告诉我,一旦解码,该对象将是一个散列,其中一个元素具有关键项和数组引用作为值。

Yes, it is a hash, but the the decode_json returns a reference, in this case, the reference to hash. (from the docs)

是的,它是一个散列,但是decode_json返回一个引用,在本例中是对hash的引用。 (来自文档)

expects an UTF-8 (binary) string and tries to parse that as an UTF-8 encoded JSON text, returning the resulting reference.

期望UTF-8(二进制)字符串并尝试将其解析为UTF-8编码的JSON文本,并返回结果引用。

In the line

在线

my $content = decode_json($json_str);

you assigning to an SCALAR variable (not to hash).

您分配给SCALAR变量(不是哈希)。

Because you know: it is a reference, you can do the next:

因为你知道:它是一个参考,你可以做下一个:

printf "reftype:%s\n", ref($content);
#print: reftype:HASH       ^   
           #therefore the  +------- is a SCALAR value containing a reference to hash

It is a hashref - you can dump all keys

它是一个hashref - 你可以转储所有密钥

print "key: $_\n" for keys %{$content}; #or in short %$content
#prints: key: items

also you can assing the value of the "items" (arrayref) to an scalar variable

你也可以将“items”(arrayref)的值赋予标量变量

my $aref = $content->{items};   #$hashref->{key}
#or
#my $aref = ${$content}{items}; #$hash{key}

but NOT

#my $aref = $content{items};    #throws error if "use strict;"
#Global symbol "%content" requires explicit package name at script.pl line 20.

The $content{item} is requesting a value from the hash %content and you never defined/assigned such variable. the $content is an scalar variable not hash variable %content.

$ content {item}正在请求散列%内容中的值,并且您从未定义/分配此类变量。 $ content是标量变量而非散列变量%content。

{
    #in perl 5.20 you can also
    use 5.020;
    use experimental 'postderef';
    print "key-postderef: $_\n" for keys $content->%*;
}

Now step deeper - to the arrayref - again you can print out the reference type

现在再深入 - 到arrayref - 再次打印出引用类型

printf "reftype:%s\n", ref($aref);
#reftype:ARRAY

print all elements of array

打印数组的所有元素

print "arr-item: $_\n" for @{$aref};

but again NOT

但同样不是

#print "$_\n" for @aref;
#dies: Global symbol "@aref" requires explicit package name at script.pl line 37.

{
    #in perl 5.20 you can also
    use 5.020;
    use experimental 'postderef';
    print "aref-postderef: $_\n" for $aref->@*;
}

Here is an simple rule:

这是一个简单的规则:

my @arr;               #array variable
my $arr_ref = \@arr;   #scalar - containing a reference to @arr

@{$arr_ref} is the same as @arr 
 ^^^^^^^^^^ - array reference in curly brackets

If you have an $arrayref - use the @{$array_ref} everywhere you want use the array.

如果您有$ arrayref - 请在任何地方使用@ {$ array_ref}来使用数组。

my %hash;              #hash variable
my $hash_ref = \%hash; #scalar - containing a reference to %hash

%{$hash_ref} is the same as %hash
 ^^^^^^^^^^^ - hash reference in curly brackets

If you have an $hash_ref - use the %{$hash_ref} everywhere you want use the hash.

如果你有$ hash_ref - 在你想要的任何地方使用%{$ hash_ref}来使用哈希。

For the whole structure, the following

对于整个结构,如下

say $content->{items}->[0];
say $content->{items}[0];
say ${$content}{items}->[0];
say ${$content}{items}[0];
say ${$content->{items}}[0];
say ${${$content}{items}}[0];

prints the same value 1.

打印相同的值1。

#2


4  

$content is a hash reference, so you always need to use an arrow to access its contents. $content{items} would refer to a %content hash, which you don't have. That's where you're getting that "use of uninitialized value" error from.

$ content是哈希引用,因此您始终需要使用箭头来访问其内容。 $ content {items}将引用您没有的%内容哈希。这就是你从“使用未初始化的值”错误的地方。

#3


0  

I actually asked a similar question here

我其实在这里问了一个类似的问题

The answer:

In Perl, a function can only really return a scalar or a list.

在Perl中,函数只能真正返回标量或列表。

Since hashes can be initialized or assigned from lists (e.g. %foo = (a => 1, b => 2)), I guess you're asking why json_decode returns something like { a => 1, b => 2 } (a reference to an anonymous hash) rather than (a => 1, b => 2) (a list that can be copied into a hash).

由于哈希可以从列表初始化或分配(例如%foo =(a => 1,b => 2)),我想你问为什么json_decode返回类似{a => 1,b => 2}的东西(引用匿名哈希)而不是(a => 1,b => 2)(可以复制到哈希中的列表)。

I can think of a few good reasons for this:

我可以想到几个很好的理由:

in Perl, an array or hash always contains scalars. So in something like { "a": { "b": 3 } }, the { "b": 3 } part has to be a scalar; and for consistency, it makes sense for the whole thing to be a scalar in the same way.

在Perl中,数组或散列总是包含标量。所以像{“a”:{“b”:3}}之类的东西,{“b”:3}部分必须是标量;为了保持一致性,整个事物以同样的方式成为标量是有道理的。

if the hash is quite large (many keys at top-level), it's pointless and expensive to iterate over all the elements to convert it into a list, and then build a new hash from that list. in JSON, the top-level element can be either an object (= Perl hash) or an array (= Perl array). If json_decode returned a list in the former case, it's not clear what it would return in the latter case. After decoding the JSON string, how could you examine the result to know what to do with it? (And it wouldn't be safe to write %foo = json_decode(...) unless you already knew that you had a hash.) So json_decode's behavior works better for any general-purpose library code that has to use it without already knowing very much about the data it's working with.

如果散列非常大(*的许多键),迭代所有元素以将其转换为列表,然后从该列表构建新的散列是毫无意义和昂贵的。在JSON中,*元素可以是对象(= Perl哈希)或数组(= Perl数组)。如果json_decode在前一种情况下返回一个列表,则不清楚在后一种情况下它会返回什么。解码JSON字符串后,您如何检查结果以了解如何处理它? (并且编写%foo = json_decode(...)是不安全的,除非你已经知道你有一个哈希。)所以json_decode的行为对任何必须使用它而不必知道的通用库代码更有效。非常关心它正在使用的数据。

I have to wonder exactly what you passed as an array to json_decode, because my results differ from yours.

我不得不想知道你作为数组传递给json_decode的确切内容,因为我的结果与你的不同。

#!/usr/bin/perl

use JSON qw (decode_json);
use Data::Dumper;
my $json = '["1", "2", "3", "4"]';

my $fromJSON = decode_json($json);

print Dumper($fromJSON);

The result is $VAR1 = [ '1', '2', '3', '4' ];

结果是$ VAR1 = ['1','2','3','4'];

Which is an array ref, where your result is a hash ref

哪个是数组引用,其结果是哈希引用

So did you pass in a hash with element items which was a reference to an array?

那么你是否传递了一个带有元素项的哈希值,这是一个对数组的引用?

In my example you would get the array by doing

在我的例子中,你将通过这样做获得数组

my @array = @{ $fromJSON };

In yours

my @array = @{ $content->{'items'} }

#4


0  

I don't understand why you dislike the arrow operator so much!

我不明白为什么你这么不喜欢箭头操作员!

The decode_json function from the JSON module will always return a data reference.

JSON模块中的decode_json函数将始终返回数据引用。

Suppose you have a Perl program like this

假设您有这样的Perl程序

use strict;
use warnings;

use JSON;

my $json_data = '{ "items": [ 1, 2, 3, 4 ] }';

my $content = decode_json($json_data);

use Data::Dump;
dd $content;

which outputs this text

输出此文本

{ items => [1 .. 4] }

showing that $content is a hash reference. Then you can access the array reference, as you found, with

显示$ content是哈希引用。然后,您可以访问数组引用,如您所见

dd $content->{items};

which shows

[1 .. 4]

and you can print the first element of the array by writing

你可以通过写作打印数组的第一个元素

print $content->{items}[0], "\n";

which, again as you have found, shows just

再次,正如你所发现的,只显示

1

which is the first element of the array.

这是数组的第一个元素。

As @cjm mentions in a comment, it is imperative that you use strict and use warnings at the start of every Perl program. If you had those in place in the program where you tried to access $content{items}, your program would have failed to compile, and you would have seen the message

正如@cjm在评论中提到的那样,必须在每个Perl程序的开头使用严格和使用警告。如果你在试图访问$ content {items}的程序中有那些,你的程序将无法编译,你会看到这条消息

Global symbol "%content" requires explicit package name

which is a (poorly-phrased) way of telling you that there is no %content so there can be no items element.

这是一种(措辞不当)告诉你没有%内容的方式,所以没有item元素。

The scalar variable $content is completely independent from the hash variable %content, which you are trying to access when you write $content{items}. %content has never been mentioned before and it is empty, so there is no items element. If you had tried @{$content->{items}} then it would have worked, as would @{${$content}{items}}

标量变量$ content完全独立于您在编写$ content {items}时尝试访问的哈希变量%content。之前从未提及%content,它是空的,因此没有items元素。如果您尝试了@ {$ content - > {items}},那么它就会起作用,就像@ {$ {$ content} {items}}一样

If you really have a problem with the arrow operator, then you could write

如果你对箭头操作符确实有问题,那么你可以写

print ${$content}{items}[0], "\n";

which produces the same output; but I don't understand what is wrong with the original version.

产生相同的输出;但我不明白原版本有什么问题。