假设我有 this文本文件中的 JSON:
{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}
使用 Perl,我已将文件读入一个名为 $json_obj
的 JSON 对象。使用 JSON::XS。如何搜索
$json_obj
对于名为 name
的所有节点并返回/打印以下内容作为结果/输出:widget->window->name: main_window
widget->image->name: sun1
widget->text->name: text1
笔记:->
/
(为简单起见,我将把它放在 perl $variable
中)path
匹配,例如:指定 id/colour
将返回包含名为 id
的节点的所有路径这也是一个父节点,其子节点名为 colour
/(name|alignment)/
对于“查找所有名为 name
或 alignment
在上面最后一个注释中显示搜索结果的示例:
widget->window->name: main_window
widget->image->name: sun1
widget->image->alignment: center
widget->text->name: text1
widget->text->alignment: center
由于 JSON 主要只是文本,我还不确定使用 JSON::XS 的好处,所以欢迎任何关于为什么这是更好或更坏的建议。不用说它需要递归才能搜索
n
任意级别的深度。这是我到目前为止所拥有的,但我只是其中的一部分:
#!/usr/bin/perl
use 5.14.0;
use warnings;
use strict;
use IO::File;
use JSON::XS;
my $jsonfile = '/home/usr/filename.json';
my $jsonpath = 'image/src'; # example search path
my $pathsep = '/'; # for displaying results
my $fh = IO::File->new("$jsonfile", "r");
my $jsontext = join('',$fh->getlines());
$fh->close();
my $jsonobj = JSON::XS->new->utf8->pretty;
if (defined $jsonpath) {
my $perltext = $jsonobj->decode($jsontext); # is this correct?
recurse_tree($perltext);
} else {
# print file to STDOUT
say $jsontext;
}
sub recurse_tree {
my $hash = shift @_;
foreach my $key (sort keys %{$hash}) {
if ($key eq $jsonpath) {
say "$key = %{$hash}{$key} \n"; # example output
}
if (ref $hash->{$key} eq 'HASH' ||
ref $hash->{$key} eq 'ARRAY') {
recurse_tree($hash->{$key});
}
}
}
exit;
上述脚本的预期结果将是:widget/image/src: Images/Sun.png
最佳答案
一旦 JSON 被解码,就会有一个复杂的(嵌套的)Perl 数据结构供您搜索,而您展示的代码正是针对该结构的。
但是,有一些图书馆可以提供帮助;要么完全完成这项工作,要么提供完整的、工作的和经过测试的代码,您可以根据具体需求进行微调。
模块Data::Leaf::Walker似乎合适。一个简单的例子
use warnings;
use strict;
use feature 'say';
use Data::Dump qw(dd);
use JSON;
use List::Util qw(any);
use Data::Leaf::Walker;
my $file = shift // 'data.json'; # provided data sample
my $json_data = do { local (@ARGV, $/) = $file; <> }; # read into a string
chomp $json_data;
my $ds = decode_json $json_data;
dd $ds; say ''; # show decoded data
my $walker = Data::Leaf::Walker->new($ds);
my $sep = '->';
while ( my ($key_path, $value) = $walker->each ) {
my @keys_in_path = @$key_path;
if (any { $_ eq 'name' } @keys_in_path) { # selection criteria
say join($sep, @keys_in_path), " => $value"
}
}
这个“walker”遍历数据结构,保留每个叶子的键列表。这就是使该模块特别适合您的任务的原因,并且与许多其他模块相比,其目的简单。请参阅文档。以上打印,用于问题中提供的示例数据
小部件->窗口->名称 => main_window
小部件->文本->名称=> text1
小部件->图像->名称 => sun1
在上面的代码中选择键路径的标准的实现相当简单,因为它检查
'name'
路径中的任何位置,一次,然后打印整个路径。虽然问题没有指定如何处理路径中较早的匹配项或多个匹配项,但这可以调整,因为我们始终拥有完整路径。您的愿望 list 的其余部分也很容易实现。细读
List::Util
和 List::MoreUtils寻求阵列分析的帮助。Data::Traverse 是另一个模块,它是满足可能的特定需求的一个很好的起点。 .特别简单,在70-odd lines of code ,所以很容易定制。
关于json - 如何递归搜索与给定模式匹配的所有节点的 JSON 文件并将 JSON 'path' 返回到节点及其值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66287984/