2014-09-20 60 views
4

我对访问已解码的一些JSON数据的内容感到困惑。这里是一个例子在Perl中解码和使用JSON数据

我不明白为什么这个解决方案的工作原理和我自己没有。我的问题是改写如下

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

此时我的JSON数据已经变成这个

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

我的猜测告诉我,一旦解码,对象将是与具有一个元素的哈希键items和数组引用作为值。

$content{'items'}[0] 

其中$content{'items'}将获得的数组引用,并且外$...[0]将访问的第一个元素阵列中把它解释为一个标量。但是这不起作用。我得到一个错误信息use of uninitialized value [...]

但是,以下不工作:

$content->{items}[0] 

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

问题

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

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

+2

阅读[perlreftut](http://perldoc.perl.org/perlreftut.html)了解有关参考文献及其用法的信息。 – 2014-09-20 16:00:00

+2

你的第一个问题是没有严格使用'',这会导致你的错误。 – cjm 2014-09-20 18:04:12

+0

Re“Wny does'$ content {'items'}'不返回数组引用吗?”因为您从未将任何内容分配给该变量“%content”。 – ikegami 2014-09-20 18:09:35

回答

4

$content是一个哈希引用,所以你总是需要使用箭头来访问它的内容。 $content{items}将引用一个%content散列,您没有。这就是你从那里“使用未初始化值”错误的地方。

+2

取消引用时使用调用箭头的另一种方法是按照[perlref](http://perldoc.perl.org/perlref.html#Using-References)文档使用符号'$$ content {items}'。 – Chris 2014-09-21 19:39:34

+1

TMTOWTDI再次袭击! – 2014-09-21 22:09:05

0

我居然问过类似的问题here

答案:

在Perl,功能真的只能返回一个标量或列表。因为哈希可以从列表中初始化或分配(例如%foo =(a => 1,b => 2)),我想你是问为什么json_decode返回类似于{a => 1,b = > 2}(对匿名散列的引用)而不是(a => 1,b => 2)(可以复制到散列中的列表)。

我能想到的几个很好的理由:

在Perl,一个数组或哈希

总是包含标量。所以在{“a”:{“b”:3}}中,{“b”:3}部分必须是标量;为了一致性,整个事物以相同的方式成为标量是有意义的。

如果散列值非常大(顶级许多键),则遍历所有元素以将其转换为列表,然后从该列表构建新的散列是没有意义的且代价昂贵。 在JSON中,顶层元素可以是对象(= Perl哈希)或数组(= Perl数组)。如果json_decode在前一种情况下返回一个列表,则不清楚在后一种情况下会返回什么。在解码JSON字符串之后,如何检查结果以了解如何处理它? (除非你已经知道你有一个散列,否则编写%foo = json_decode(...)是不安全的。)因此,json_decode的行为对于任何通用库代码来说都更好,因为它必须在不知道的情况下使用它非常关注它正在使用的数据。

我不得不怀疑你作为一个数组传递给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); 

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

这是一个数组引用,你的结果是一个哈希裁判

那你有没有在这是一个数组的引用元素项散列通?

在我的例子,你会做

my @array = @{ $fromJSON }; 

在你

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

我不明白,为什么你不喜欢的箭头操作这么多的拿到阵!

decode_json函数从JSON模块将总是返回一个数据引用。

假设有这样

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; 

,其输出该文本

{ items => [1 .. 4] } 

表示$content散列引用 Perl程序。然后可以访问数组引用,因为你发现,随着

dd $content->{items}; 

表示

[1 .. 4] 

,你可以通过写

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

其中打印所述阵列的所述第一元件,再次如您所见,只显示

1 

这是数组的第一个元素。

正如评论@cjm提到,它是势在必行use strictuse warnings的Perl程序的启动。如果你有那些在您试图访问$content{items}程序的地方,你的程序会无法编译,你会看到消息

Global symbol "%content" requires explicit package name 

这是告诉你的(不良的措辞)的方式没有%content,所以不可能有items元素。

变量$content哈希变量%content,您正在尝试当你写$content{items}访问完全独立%content以前从未提及,它是空的,所以没有items元素。如果你曾试图@{$content->{items}}那么它会工作,如将@{${$content}{items}}

如果你真的用箭头运营商有问题,那么你可以写

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

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

5

初学者对初学者的回答:)当然不应该像专业人士一样,但也许可以帮助你。

您写道:

我的猜测告诉我,一旦解码,对象将是与具有关键项目和数组引用作为值 一个元素的哈希值。

是的,它是一个散列,但decode_json返回一个引用,在这种情况下,引用散列。 (从文档)

期望的UTF-8(二进制)串并尝试解析 作为UTF-8编码的JSON文本, 返回结果参考

在您指派给标量变量的线

my $content = decode_json($json_str); 

(未散列)。

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

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

这是一个hashref - 你可以转储所有按键

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

也可以assing的价值在 “项目”(数组引用)到一个标量变量

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

NOT

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

$content{item}从散列%content请求值和你从未定义/分配这样的变量。 $content是一个标量变量而不是散列变量%content

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

现在更深一步 - 对数组引用 - 你可以再次打印出的引用类型

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

打印数组的所有元素

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

却又

#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->@*; 
} 

下面是一个简单的规则:

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 

如果你有一个$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 

如果你有一个$hash_ref - 使用%{$hash_ref}无处不在,你想使用的哈希值。

对于整个结构,以下

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

打印相同值1