如何将 Perl 对象转换为 JSON,反之亦然
Posted
技术标签:
【中文标题】如何将 Perl 对象转换为 JSON,反之亦然【英文标题】:How to convert Perl objects into JSON and vice versa 【发布时间】:2011-05-10 06:52:46 【问题描述】:我在文件 Point.pm
中定义了一个 Point 对象,如下所示:
package Point;
sub new
my ($class) = @_;
my $self =
_x => 0,
_y => 0,
;
return bless $self => $class;
sub X
my ($self, $x) = @_;
$self->_x = $x if defined $x;
return $self->_x;
sub Y
my ($self, $y) = @_;
$self->_y = $y if defined $y;
return $self->_y;
1;
现在,当我使用JSON 通过以下代码将对象转换为 JSON 时:
use JSON;
use Point;
Point $p = new Point;
$p->X(20);
$p->Y(30);
my $json = encode_json $p;
我收到以下错误:
encountered object 'Point=HASH(0x40017288)', but neither allow_blessed nor convert_blessed settings are enabled at test.pl line 28
如何使用 JSON 模块在 JSON 和对象之间进行转换?
【问题讨论】:
除非您特别需要 JSON,否则我建议您使用 YAML 来完成此任务。 JSON 没有语法来指示某物是一个对象。 YAML 可以。您必须手动将某些东西组合在一起或使用 JSON 语言扩展,如 JSYNC。如果您只需要序列化 Perl 对象,请使用 Data::Dumper 或 Storable。 我最初是在 XML 中开发解决方案,但我发现 JSON 可能会修剪字符串,因为它使用 STDIN 到其他脚本,但是由于 JSON 的复杂性和不可读性,我决定切换回 XML,它易于解析。 【参考方案1】:警告告诉您大部分问题。除非您告诉JSON
如何处理blessed 引用(Perl 对象),否则JSON
只处理未受祝福的数据结构。
您可以convert_blessed
,也可以allow_blessed
。对于allow_blessed
,它说:
如果
$enable
为false(默认),则encode遇到祝福对象时会抛出异常。
Point 是一个对象类,因此Point
的实例是一个祝福引用,因此JSON
的默认值是抛出异常。
如果您启用convert_blessed
,它将在您的对象上调用TO_JSON
方法。使用 simple 对象,例如 Point
(不包含祝福成员的对象),您可以轻松地做到这一点:
sub TO_JSON return % shift() ;
如果你必须降低一个结构,它会得到一个很多的毛发。
下面的 cmets 中有人说我没有介绍如何从 JSON 中获取对象out。
基础很简单。所以就到这里了
my $object = bless( JSON->new->decode( $json_string ), 'ClassIWant' );
我主要介绍了阻止您将受祝福的对象简单地序列化为 JSON 的部分。
反序列化的基础很简单,就像序列化的基础很简单——只要你知道诀窍。方式没有错误,只是找到你需要的东西并将它祝福到正确的班级的任务。
如果您希望将代码与对象耦合,那么您将知道必须祝福什么以及必须祝福什么。如果您想要完全解耦的代码,这在 Perl 中并不比在 javascript 本身中更难或更容易。
您将不得不在 JSON 中序列化一个 标记。如果我需要这样的东西,我会在祝福对象中插入一个'__CLASS__'
字段。而在反序列化的时候,我会通过结构降下来,祝福一切都是这样的:
bless( $ref, delete $ref->__CLASS__ );
但正如我所说,这在 Perl 中既不简单也不困难,因为 JSON 对所有语言提出了相同的挑战。
正如 Schwern 在顶部的评论中所建议的那样,YAML 更适合用于序列化和反序列化对象,因为它具有 notation。 JSON 为您提供关联数组或数组。
【讨论】:
得到语法:$json->allow_blessed->convert_blessed->encode($blessed_object) 或者:to_json($blessed_object,allow_blessed=>1,convert_blessed=>1) 这不符合他问题的第二部分:“反之亦然”。最难的部分是在解码后将 JSON 转换为 Perl 对象。 @PeterV.Mørch,这并不难。 Perl 可以将许多结构化数据语言转换为散列,而您只需将该散列祝福为所需的类。我详述的实际上是 hard 部分,因为当您简单地尝试将对象转换为 JSON 时,JSON 规则会导致错误。 @Axeman :-) 取决于上下文,我猜。我希望使用 JSON 作为套接字上的透明编码来发送 objects,但我事先不知道这些对象的类型。但是我看到你已经在这方面大大扩展了你的问题,建议使用魔术字符串__CLASS__
,就像MooseX::Storage 一样。伟大的!我会使用Data::Walk。【参考方案2】:
您是否尝试按照错误消息的建议阅读allow_blessed 和convert_blessed 选项上的JSON documentation?这应该解释了如何将 Perl 对象转换为 JSON。
走另一条路更难,因为 JSON 不是YAML,也不是为了反序列化为像 Perl 那样的基于类的对象系统。您可以尝试使用 filter_json_object 或 filter_json_single_key_object 选项,或者您可以对解码后的 JSON 进行后处理并自己创建对象。
【讨论】:
【参考方案3】:你需要JSYNC。
use JSYNC;
use Point;
my $p = Point->new;
$p->X(20);
$p->Y(30);
my $jsync = JSYNC::dump($p, pretty => 1);
"!" : "!perl/hash:Point",
"_x" : "20",
"_y" : "30"
【讨论】:
这是一个非常早期的 JSYNC 版本,除非你知道自己在做什么,否则根本不应该使用它。我需要一个像 JSON 这样的生产就绪模块。 @daxim 刚刚测试了一下,发现一个小问题:值是json stings
,但我们需要json numbers
。有没有办法将这些值构建为数字(在文档中没有找到任何内容)
继承 JSYNC 并更改 info
方法以在遇到 Perl scalar
类型时区分 numbers 和非数字。【参考方案4】:
您可能会发现将类转换为Moose 并使用MooseX::Storage 对其进行序列化和反序列化很有用。
【讨论】:
我喜欢使用 Moose,但是我运行的服务器使用的是旧版本的 Perl 5.8.8。恐怕服务器用于生产,升级 Perl 会破坏一些生产脚本。 @Ibrahim:Moose 与 perl5.8.8 兼容;我在自己的生产环境中将它与那个版本的 Perl 一起使用。以上是关于如何将 Perl 对象转换为 JSON,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章
如何在python3.6中将字符串转换为唯一的整数,反之亦然(在0到255之间)