使用Perl解析JSON文件

6
我将尝试在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};

但是我没有得到任何输出。

有人能告诉我错在哪里吗?


1
使用 http://jsonlint.com/ 这个页面来验证或检查 JSON。 - Zelldon
2个回答

26
你的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.com或随附 JSON::XS 来自CPAN的 json_xs 工具来验证JSON格式是否正确。

JSON可以描述复杂的数据结构,因此将其解析到Perl中会得到一个复杂的数据结构。尝试使用 Data::DumperData::PrinterData::TreeDumper 查看数据结构。


你的 do open(...) 函数是否会泄露已打开的文件? - TheCppZoo
2
当文件句柄超出作用域时,它会被关闭。 - wsdookadr

6
除了在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
}

这里有一个替代方案 map { print $_->{name}; } @{$data->{data}};。或者你可以使用 print join(",",(map{ $_->{name}} @{$data->{data}}));。虽然这仍然是一个循环,但为什么需要一个非循环的解决方案呢? - wsdookadr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接