Perl 解码和编码 JSON 保持顺序



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

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

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

您需要使用流式 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]]}]

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

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

然后我按第二个参数的顺序浏览键,并将结果放入新的绑定 (IxHash) 哈希和 json 编码中。

非常遗憾的是,没有perl json解码器可以保留键顺序,而我使用的其他所有东西,至少在这个项目中,都这样做(php,postgres,firefox,chrome)。

@soger,感谢您 5 年前在上面的评论中的想法!

我研究了 JSON::P P 代码,我只需要在名为 object() 的函数的开头添加一个与 IxHash 的联系。

出色的解决方案! 谢谢你的想法。 我想出了如何使用Monkey::Patch模块来包装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% 的逐字节相同。👍

(当然,理想情况下,JSON::PP应该将其作为开箱即用的内置选项提供!

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

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

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

最新更新