如何将Perl对象转换为JSON,反之亦然

时间:2010-11-15 14:48:51

标签: perl json

我在文件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转换为对象?

4 个答案:

答案 0 :(得分:21)

警告告诉你大部分错误。除非你告诉JSON如何处理祝福的引用(Perl对象),JSON只处理未受祝福的数据结构。

您可以convert_blessedallow_blessed。对于allow_blessed,它说:

  

如果$enable为false(默认值),则encode会在遇到祝福对象时抛出异常。

Point 是一个对象类,因此Point的实例是一个受祝福的引用,因此JSON的默认值是抛出异常。

如果您启用convert_blessed,则会在您的对象上调用TO_JSON方法。使用简单的对象(如Point(不包含祝福成员的对象)),您可以轻松地执行此操作:

sub TO_JSON { return { %{ shift() } }; }

如果你必须下降一个结构,它将获得 lot 发型。


下面评论中有人说我没有介绍如何获取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更适合序列化和反序列化对象,因为它有符号。 JSON为您提供关联数组或数组。

答案 1 :(得分:5)

您是否尝试按照错误消息的建议阅读JSON documentationallow_blessed选项中的convert_blessed?这应该解释如何将Perl对象转换为JSON。

另一种方式更难,因为JSON不是YAML,并且没有被设计为反序列化为像Perl这样的基于类的对象系统。您可以尝试使用filter_json_objectfilter_json_single_key_object选项,也可以对已解码的JSON进行后期处理并自行创建对象。

答案 2 :(得分: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"
}

答案 3 :(得分:2)

您可能会发现将类转换为Moose并使用MooseX::Storage对其进行序列化和反序列化非常有用。