【问题标题】:Converting JSON string to Perl/Moose objects将 JSON 字符串转换为 Perl/Moose 对象
【发布时间】:2012-08-28 04:47:18
【问题描述】:

我有一个 JSON 字符串,例如

use JSON::XS qw(decode_json);
say Dumper( decode_json($json) );

将产生:

$VAR1 = {
    'Fname' => 'SomeFname',
    'Lname' => 'SomeLname',
    'Addr' => {
          'Street => 'Somestreet',
          'Zip' => '00000',
    },
};

我正在寻找一种将 JSON 字符串(或 perl 结构)“转换”为 Perl/Moose 对象的简单方法,例如:

 package My;
 use Moose;
 has 'Fname' => (is => 'rw', isa => 'Str');
 has 'Lname' => (is => 'rw', isa => 'Str');
 has 'Addr' =>  (is => 'rw', isa => 'My::Addr');

 package My::Addr;
 use Moose;
 has 'Street' => (is => 'rw', isa => 'Str');
 has 'Zip' => (is => 'rw', isa => 'Str');

问题有两部分:

  1. 基于 JSON 字符串定义 Moose 类层次结构(一次性)
  2. 使用来自 JSON 的真实值初始化对象实例(对于每个 JSON)

我对 Moose 不是很熟练,所以需要一些链接来解决这个特定问题。

(Moose 很大 - 所以在 CPAN 中阅读 所有内容 肯定会有所帮助,但对于开始来说太多了。因此我正在寻找在现实世界问题中逐步学习的方法 - 比如以上)。

主要问题是:

  • 是否可以从数据结构中生成 Moose 类定义(perl 源)?存在这样的CPAN模块吗?
  • 当我得到类层次结构时(例如,如果这里没有任何帮助,我可以手动编写它们),从 JSON 创建(初始化)它们的实例的最简单方法是什么?

【问题讨论】:

    标签: json perl serialization code-generation moose


    【解决方案1】:

    是否可以从数据结构生成 Moose 类定义(perl 源)?存在这样的CPAN模块吗?

    是的。但是,您如何做到这一点将在很大程度上取决于您希望完成的任务。最简单的方法是在基于 JSON 的内存中构建属性。例如,您可以在运行时从 JSON 文件中实例化元类对象,如下所示:

    sub infer_class_from_hash {
        my ($input) = @_;
    
        # Makes for ugly class names, but does the job
        my $meta = Moose::Meta::Class->create_anon_class;
    
        for my $key (keys %$input) {
            my $value = $input->{$key};
    
            my $type;
            my $coerce = 0;
    
            # Handle nested objects in the JSON as Moose objects
            if (ref $value eq 'HASH') {
                my $inner_meta = infer_class_from_hash($value);
                $type = $meta->name;
    
                # We provide an automatic HASH -> Class coercion
                $coerce = 1;
            }
    
            # Assume arrays are always of scalars, could be extended to handle objects
            elsif (ref $value eq 'ARRAY') {
                $type = 'ArrayRef',
            }
    
            # Assume anything else is string-ish
            else {
                $type = 'Str',
            }
    
            $meta->add_attribute($key =>
                is => 'rw',
                isa => $type,
                coerce => $coerce,
            );
        }
    
        # Create a coercion that makes instantiating from the JSON tree dead simple
        use Moose::Util::TypeConstraints;
        coerce $meta->name => from 'HashRef' => via { $meta->name->new($_) };
        no Moose::Util::TypeConstraints;
    
        return $meta;
    }
    

    所有这些甚至还没有开始进入你可以做的事情。您可以应用角色、自定义基类、添加方法等。不过,这是动态构建 Moose 类的基础。

    如果您想要一个代码生成器,将实际 Moose 类输出为可以构建一次然后稍后加载的文件,请随心所欲。我只是编写一个与上面类似的程序,但输出一组 .pm 文件,其中包含自动生成的 Moose 类定义。

    当我得到类层次结构时(例如,如果这里没有任何帮助,我可以手动编写它们),从 JSON 创建(初始化)它们的实例的最简单方法是什么?

    use JSON qw( from_json );
    my $hash = from_json("...");
    my $meta = infer_class_from_hash($hash);
    
    my $obj = $meta->name->new($hash);
    

    这里的关键是我们如何使用 Moose 类型强制将读取的 JSON 对象自动转换为 Moose 类实例。如果您有多个序列化方案或想以其他方式使用类型约束,您可以为所有这些设置一个基类(在对create_anon_class 的调用中),它提供了to_json/from_json 处理方法JSON 输入中嵌套对象的情况。

    【讨论】:

    猜你喜欢
    • 2012-07-29
    • 2019-08-27
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 2012-06-14
    • 2012-02-20
    • 2015-01-03
    相关资源
    最近更新 更多