【发布时间】:2019-02-24 04:34:11
【问题描述】:
我有一个 JSON 格式的数据流,我的脚本可以从内部网站访问该数据流。我的脚本使用 JSON.pm 将 JSON 转换为 perl 哈希(我在 RHEL 6.9 上使用 perl 5.10.1)
在这个散列中有多个嵌套散列和嵌套数组,其中一些嵌套在大散列内的其他散列/数组中。
我需要遍历散列的整个结构,包括所有数组和嵌套散列,并删除整个结构中任何位置的任何键,这些键与任何其他键具有相同的名称(尽管仅适用于特定键名)。
此外,由于数据的结构,一些嵌套散列只有现在被删除的键,一些键的值作为空散列。我还需要删除那些其值为空哈希的键
这是我转换为 perl 后的数据:
$VAR1 = {
'cat' => 'meow',
'dog' => [
{
'a' => {
'husky' => {
'name' => 'fred'
},
'chow' => {
'name' => 'barney'
}
},
},
{
'b' => {
'husky' => 'wilma',
'lab' => 'betty'
},
'c' => 'pebbles' # yes this is intentionally a scalar in the example
},
{
'd' => {
'shihtzu' => 'bambam'
},
},
{
'e' => {
'husky' => 'dino'
},
},
],
}
我们要删除所有名为“husky”的键
它应该是这样的:
$VAR1 = {
'cat' => 'meow',
'dog' => [
{
'a' => {
'chow' => {
'name' => 'barney'
}
},
},
{
'b' => {
'labrador' => 'betty'
},
'c' => 'pebbles'
},
{
'd' => {
'shihtzu' => 'bambam'
},
},
],
}
这是我添加@Shawn 的代码并对其进行调整后得到的(这非常接近,但我们需要考虑空哈希:
$VAR1 = {
'cat' => 'meow',
'dog' => [
{
'a' => {
'chow' => {
'name' => 'barney'
}
},
},
{
'b' => {
'lab' => 'betty'
},
'c' => 'pebbles' # yes this is intentionally a scalar in the example
},
{
'd' => {
'shihtzu' => 'bambam'
},
},
{
'e' => {},
},
]
}
我尝试了一些在 SO 和 perlmonks 上其他地方发现的变体。 keys %$_ == 0、!%$_ 仅举几例。但似乎没有一个适用于这个哈希片。
代码:
use 5.008008;
use strict;
use warnings;
use English; # I know I know, don't use English...
use JSON;
use YAML::Tiny qw(Dump);
# proprietary modules I wrote added here, which themselves load in LWP, HTTP::Cookie and others, and they do the bulk of building and sending the request. They are the back end to this script's front end.
[-snipped a ton of code-]
sub _count_keys
{
my ($j, $seen) = @ARG;
my $type = ref $j;
if ($type eq "ARRAY")
{
for (@{$j})
{
_count_keys($ARG, $seen);
}
}
elsif ($type eq "HASH")
{
while (my ($key, $val) = each %{$j})
{
$seen->{$key}++;
if (ref $val)
{
_count_keys($val, $seen);
}
}
}
return $seen;
}
sub _remove_duplicate_keys
{
my ($j, $seen) = @ARG;
$seen //= _count_keys($j, {});
my $type = ref $j;
if ($type eq "ARRAY")
{
return [ map { _remove_duplicate_keys($ARG, $seen) } @{$j} ];
}
elsif ($type eq "HASH")
{
my %obj = %{$j};
delete @obj{grep { $seen->{$ARG} > 1 and $ARG eq 'keyNameToBeExcluded'} keys %obj};
# Here is where I have been putting another delete line but I can't seem to find the right parameters for the grep to make it delete the empty anon hashes. Example of what I tried is the next comment below
# delete @obj{grep { $seen->{$ARG} > 1 and keys $ARG{assetDetails} == 0 } keys %obj};
while (my ($key, $val) = each %obj)
{
if (ref $val)
{
$obj{$key} = _remove_duplicate_keys($val, $seen);
}
}
return \%obj;
}
else
{
return $j;
}
}
sub _process_json
{
my $JSONOUTPUT = shift;
my $OPTIONS = shift;
# Change true to 1 and false to 0 to prevent blessed objects from appearing in the JSON, which prevents the YAML::Tiny module from barfing
foreach (@{$JSONOUTPUT})
{
s{true(,\n)}{1$1}gxms;
s{false(,\n)}{0$1}gxms;
}
my $JSONPERLOBJ = JSON->new->utf8->decode(@{$JSONOUTPUT});
# Test code below here; real code not in use while I test getting the output right.
use Data::Dumper;
my $BEFORE = $JSONPERLOBJ;
my $AFTER = _remove_duplicate_keys($JSONPERLOBJ);
# $JSONPERLOBJ = _remove_duplicate_keys($JSONPERLOBJ);
#print Dumper $BEFORE;
print Dumper $AFTER;
exit 1;
# End test code
}
sub _main
{
[-snip private code-]
my @JSONOUTPUT = $RESPONSE->decoded_content;
my $RC = _process_json(\@JSONOUTPUT, $OPTIONS);
exit ($RC == 1)?0:1;
}
【问题讨论】:
-
[ ... ]创建一个数组。请use Data::Dumper和print Dumper \%obj让我们看到您实际拥有的东西。此外,在 Perl 中,“对象”是一个被祝福到一个类中的数据项。您在这里拥有的只是一个数据结构。 -
这是(表示)JSON 返回的内容吗?那将是一个 hashref,
my $hr = {...}。您正在显示一个 arrayref[...],分配给一个哈希 (%) 变量。 -
编辑了 OP。没有理由对一个简单的错字投反对票。我不能给你一个转储,因为它包含数千行信息,其中大部分是敏感的。以我给出的例子为例,因为这就是我所能提供的。 @zdim 是的,它代表 JSON 数据。我手动输入了示例并使用了错误的符号。我的错。我们现在可以专注于实际问题吗?
-
感谢您的更新,但是您显示的数据结构是不可能的,如果您尝试编译它,您会看到
Odd number of elements in anonymous hash错误。请转储您的真实数据,否则我们无法帮助您, -
OP 当然可以使用改进,但不难理解他想要做什么,因为他有 JSON,他想删除在 anywhere 中找到的具有重复键的条目JSON 数据。
标签: json perl hash-of-hashes