Perl解码和编码JSON保持顺序

6psbrbz9  于 2023-10-24  发布在  Perl
关注(0)|答案(5)|浏览(174)

我在一个文本数据库字段中有一个JSON编码的图表配置,格式为:

{"Name":[[1,1],[1,2],[2,1]],"Name2":[[3,2]]}

这些ID的第一个数字是另一个表的主键。我想在删除行时使用触发器删除这些条目,plperl函数将是很好的,但它不保留散列的顺序,并且顺序在此项目中很重要。我可以做什么(不改变json编码配置的格式)?注意:图表名称可以包含任何字符,所以很难用正则表达式来实现。

deyfvvtc

deyfvvtc1#

你需要使用一个流JSON解码器,比如JSON::Streaming::Reader。然后你可以将你的JSON存储为一个键/值对数组,而不是哈希。
如何使用它的实际实现在很大程度上取决于数据的结构,但是给出了一个简单的例子......这里有一个简单的实现。

use strict;
use warnings;
use JSON::Streaming::Reader;
use JSON 'to_json';

my $s = '{"Name":[[1,1],[1,2],[2,1]],"Name2":[[3,2]]}';

my $jsonr = JSON::Streaming::Reader->for_string($s);

my @data;
while (my $token = $jsonr->get_token) {
    my ($key, $value) = @$token;
    if ($key eq 'start_property') {
        push @data, { $value => $jsonr->slurp };
    }   
}   

print to_json(\@data);

此脚本的输出始终为:

[{"Name":[[1,1],[1,2],[2,1]]},{"Name2":[[3,2]]}]
z5btuh9x

z5btuh9x2#

好吧,我设法解决了我的问题,但它不是一个通用的解决方案,所以它可能不会帮助休闲读者.无论如何,我得到了使用数据库的帮助键的顺序,我这样调用我的函数:

SELECT remove_from_chart(
    chart_config,
    array(select * from json_object_keys(chart_config::json)),
    id);

然后我按照第二个参数的顺序遍历了这些键,并将结果放入一个新的绑定(IxHash)哈希中,然后用json对其进行编码。
很遗憾的是,没有perl json解码器可以保留键的顺序,而我所使用的其他东西,至少在这个项目中,都是这样(php,postgres,firefox,Chrome)。

rdlzhqv9

rdlzhqv93#

@soger,谢谢你5年前在上面评论的想法!
我查看了JSON::PP代码,我只需要在名为object()的函数的开头添加一个绑定到IxHash。
绝妙的解决方案!谢谢你的想法。我想出了如何实现这一点,使用Monkey::Patch模块 Package JSON::PP::object()函数,使其使用Tie::IxHash,而不接触安装的JSON::PP文件:

use Monkey::Patch qw[patch_package];

# Monkey-patch JSON::PP::object() subroutine to use Tie::IxHash.
my $handle = patch_package 'JSON::PP' => 'object' => sub {
  my $orig = shift;
  my %obj;
  tie %obj, 'Tie::IxHash' or die "tie(\%obj, 'Tie::IxHash') failed!\n";
  $orig->(\%obj)
};

运行上述代码后,只要$handle仍在作用域中,JSON::PP::decode_json将对所有JSON对象使用Tie::IxHash。我测试了阅读JSON文件,使用JSON::PP::decode_json解码,然后使用JSON::PP::encode_json将生成的数据结构编码回JSON,并将其写入新的JSON文件。然后我通过jq .运行原始JSON文件和新JSON文件,以规范化格式并比较结果。它们是100%逐字节相同的。👍
(Of当然,理想情况下,JSON::PP应该将其作为开箱即用的内置选项提供!)

wqsoz72f

wqsoz72f4#

JSON对象是无序的。您必须以某种方式将所需的顺序编码到数据中

{"Name":[[1,1],[1,2],[2,1]],"Name2":[[3,2]], "__order__":["Name","Name2"]}

[{"Name":[[1,1],[1,2],[2,1]]},{"Name2":[[3,2]]}]
mbyulnm0

mbyulnm05#

可能你想要像SAX解析器一样的JSON数据流解码器。如果是这样,请参阅JSON::Streaming::ReaderJSON::SL

相关问题