如何将 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,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中将 Xml 转换为 Json,反之亦然

将图像转换为 JSON 时发生错误(数据损坏),反之亦然

如何在python3.6中将字符串转换为唯一的整数,反之亦然(在0到255之间)

java 将JSONObject转换为JSON String的Java程序,反之亦然

从核心数据创建 json 字符串,反之亦然?

将字节数组放入 JSON,反之亦然