从复杂的 JSON 结构中提取数据

Extracting data from complex JSON structure

我正在尝试从以下 json 结构中提取一些数据:

{
    "numFailedTestSuites": 0,
    "numFailedTests": 0,
    "numPassedTestSuites": 7,
    "numPassedTests": 29,
    "numPendingTestSuites": 0,
    "numPendingTests": 0,
    "testResults": [
        {
            "assertionResults": [
                {
                    "ancestorTitles": [
                        "propertyReader"
                    ],
                    "failureMessages": [],
                    "fullName": "propertyReader Test method: readPropertyFile",
                    "location": null,
                    "status": "passed",
                    "title": "Test method: readPropertyFile"
                }
            ]
        },
        {
            "assertionResults": [
                {
                    "ancestorTitles": [
                        "Transform Angle"
                    ],
                    "failureMessages": [],
                    "fullName": "Transform Angle Test Method: rotationMatrix",
                    "location": null,
                    "status": "passed",
                    "title": "Test Method: rotationMatrix"
              }
            ]
        }
    ]
}

特别是,我需要访问状态和头衔。这是我写的:

my $dir = getcwd();
my $jsonFilePath="testResult.json";
my $finalPath=$dir."/".$jsonFilePath;

print "json file path is ",$finalPath;
my $json = $finalPath;

my $data = do {
    open my $fh, '<', $json;
    local $/;
    decode_json(<$fh>);
};

my $results = $data->{testResults};
for my $result ( @$results ) {

    my $readings   = $result->{assertionResults};
    printf "status: %s\n", $readings->{status};
    printf "title:    %s\n", $readings->{title};
    print "\n";
}

我收到以下错误:

Pseudo-hashes are deprecated
Argument "passed" isn't numeric in hash element at line 27(printf "status: %s\n", $readings->{status};)
Bad index while coercing array into hash at line 27.

如何修复这些错误并从上面的 JSON 中提取状态和标题?

首先,您的 JSON 无效:您在最后一个 } 之前缺少一个结束 ] (这将关闭与键 [=16= 关联的数组) ]).通过添加缺少的 ] 来修复 JSON 的语法将修复以下错误消息:

, or ] expected while parsing array, at character offset 1128 (before "}\n") at ...

其次,assertionResults 包含一个 JSON 数组(然后在 Perl 中转换为 arrayref)而不是一个对象(它会被转换为 hashref)。因此,您应该在执行 $readings->{status}:

时收到此错误

Not a HASH reference at json.pl line ...

要修复它,请将 $result->{assertionResults} 视为 arrayref 而不是 hashref。看来你想做的是:

my $readings = $result->{assertionResults}[0];

也就是说,根据您的 JSON 实际可以包含的内容,您可能想要做的是:

for my $readings (@{$result->{assertionResults}}) {
    printf "status: %s\n", $readings->{status};
    printf "title:  %s\n", $readings->{title};
    print "\n";
}

或者,您可能没有按照自己的意愿构建 JSON,而是

    "assertionResults": [
        {
            "ancestorTitles": [
                "propertyReader"
            ],
            "failureMessages": [],
            "fullName": "propertyReader Test method: readPropertyFile",
            "location": null,
            "status": "passed",
            "title": "Test method: readPropertyFile"
        }
    ]

您可能想要删除括号 []

    "assertionResults":
        {
            "ancestorTitles": [
                "propertyReader"
            ],
            "failureMessages": [],
            "fullName": "propertyReader Test method: readPropertyFile",
            "location": null,
            "status": "passed",
            "title": "Test method: readPropertyFile"
        }

请调查以下代码片段是否符合您的问题。

use strict;
use warnings;
use feature 'say';

use JSON;

my $json = do { local $/; <DATA> };
my $data = from_json($json);

say "$_->{assertionResults}[0]{title}   $_->{assertionResults}[0]{status}"
    for  @{$data->{testResults}};


__DATA__
{
    "numFailedTestSuites": 0,
    "numFailedTests": 0,
    "numPassedTestSuites": 7,
    "numPassedTests": 29,
    "numPendingTestSuites": 0,
    "numPendingTests": 0,
    "testResults": [
        {
            "assertionResults": [
                {
                    "ancestorTitles": [
                        "propertyReader"
                    ],
                    "failureMessages": [],
                    "fullName": "propertyReader Test method: readPropertyFile",
                    "location": null,
                    "status": "passed",
                    "title": "Test method: readPropertyFile"
                }
            ]
        },
        {
            "assertionResults": [
                {
                    "ancestorTitles": [
                        "Transform Angle"
                    ],
                    "failureMessages": [],
                    "fullName": "Transform Angle Test Method: rotationMatrix",
                    "location": null,
                    "status": "passed",
                    "title": "Test Method: rotationMatrix"
              }
            ]
        }
    ]
}

输出

Test method: readPropertyFile   passed
Test Method: rotationMatrix     passed

注意:

my $json = do { local $/; <DATA> }; 替换为 my $json = do { local $/; <> }; 以从作为脚本参数提供的文件中读取。例如 ./script.pl datafile.json.

这种方法允许利用管道将输入数据泵送到脚本。例如 cut datafile.json | ./script.pl.