2013-03-27 201 views
4

我想解析perl中的json文件。我想提取关键的“名称”及其相应的值。 我的文件看起来像这样使用perl解析json文件

{ 
"data":[ 
    { 
     "name":"ABC", 
     "id":"123", 
    }, 
    { 
     "name":"PQR", 
     "id":"456", 
    }, 
    { 
     "name":"XYZ", 
     "id":"789", 
    } 
] 
} 

我用下面的代码尝试:

#/usr/lib/perl 
use lib qw(..); 
use LWP::Simple; 
use JSON; 
my $filename = '/file.txt'; 
my $data; 
if (open (my $json_str, $filename)) 
{ 
    local $/ = undef; 
    my $json = JSON->new; 
    $data = $json->decode(<$json_str>); 
    close($json_stream); 
} 
print $data->{name}; 

但我没有得到任何输出。

任何人都可以打电话给我什么是错的?

+0

http://jsonlint.com/使用此页面来验证或JSON – Zelldon 2013-03-27 07:16:03

回答

18

你的json文件无效。

第5,10,15行不应以逗号结尾,因为这是这些哈希的最后一个键/值对。

之后你解决这个问题,这里是你的代码的一个版本,让你期望的结果:

#/usr/lib/perl 
use strict; 
use warnings; 

use lib qw(..); 

use JSON qw(); 

my $filename = 'file.txt'; 

my $json_text = do { 
    open(my $json_fh, "<:encoding(UTF-8)", $filename) 
     or die("Can't open \$filename\": $!\n"); 
    local $/; 
    <$json_fh> 
}; 

my $json = JSON->new; 
my $data = $json->decode($json_text); 

for (@{$data->{data}}) { 
    print $_->{name}."\n"; 
} 

一些问题:

  • 您使用$json_stream$json_str。你打算在所有地方使用$json_stream来表示文件句柄
  • $data->{name}应该应用于.json文件中数组的所有成员,而不是json本身。所以你需要先遍历它们

当调试这个时,确保你的json是有效的。通过jsonlint.comjson_xs实用程序,从cpan中附带JSON::XS

JSON可以描述复杂的数据结构,所以当你将它解析成Perl时,你也会得到一个复杂的数据结构。尝试先看看数据结构使用Data::DumperData::PrinterData::TreeDumper

+0

没有你的'做开放(...)'泄漏一个打开的文件? – EdMaster 2016-07-31 01:19:16

+1

[文件句柄已关闭](http://stackoverflow.com/a/953885/827519)当它[超出范围](http://www.perlmonks.org/?node_id=287647#287686)。 – average 2016-07-31 06:55:23

4

除了在JSON字符串中有一个额外的逗号,您不会引用正确的值。始终使用

use strict; 
use warnings; 

- 他们会告诉你什么是错的。在这种情况下,您正在打印一个未定义值$data->{name},这是一个尚未分配值的变量。如果您在Data::Dumper打印解码的结构,它看起来像这样:

$VAR1 = { 
      'data' => [ 
         { 
         'name' => 'ABC', 
         'id' => '123' 
         }, 
         { 
         'name' => 'PQR', 
         'id' => '456' 
         }, 
         { 
         'name' => 'XYZ', 
         'id' => '789' 
         } 
        ] 
     }; 

正如你所看到的,$data其实是一个散列引用,其中,第一和唯一的密钥被称为'data',它的值是一个有三个数组元素,每个元素包含一个散列引用。因此,为了打印这些元素,你会做这样的事情:

print $data->{data}[0]{name}; # prints ABC 

my $aref = $data->{data}; 
for my $element (@$aref) { 
    print $element->{name};  # prints ABC, PQR, XYZ 
} 
+0

这可以做得更简洁,没有循环? – Geremia 2016-03-12 20:09:00

+0

这是另一种'map {print $ _-> {name}; } @ {$ data - > {data}};'。或者你可以'print join(“,”,(map {$ _-> {name}} @ {$ data - > {data}}));'尽管如此,它仍然是一个循环。为什么需要非循环解决方案? – average 2016-07-31 07:05:32