如何将Moose对象序列化为XML?

3
我有一堆遗留模块需要转换为基于Moose的模块。这些模块目前有“toXML”方法,使用XML::LibXML手动编写。
是否有一种模块或技术可以将Moose对象序列化为XML?
我已经查看了MooseX::Storage,但它处理的是JSON、YAML和Storage,而不是XML。在搜索Moose和XML时,会得到许多关于XML::Rabbit的参考资料,它似乎很适合将XML解析成Moose类,但没有太多关于将Moose对象序列化为XML的内容。
6年前的线程http://grokbase.com/t/perl/moose/11akp809sr/java-annotation-net-attributes-in-moose非常接近我的要求,但似乎没有后续跟进。

1
MooseX::Storage 通过使用 MooseX::Storage::Format::JSON 角色来实现。据我所见,这是唯一的 MooseX::Storage::Format 序列化角色。也许你可以自己编写一个?Format::JSON 的代码只有几十行(使用一个模块)。我不知道你需要序列化什么,但也许 XML::Dumper 可以帮助你。它声称能够处理对象。 - zdim
@zdim, 关于“From what I can see, it's the only MooseX::Storage::Format serialization role our there”,MooseX::Storage::Format::JSON、...::YAML和...::Storable都包括在MooseX::Storage中。 - ikegami
@Blaise Pascal,因此编写MooseX::Storage::Format::XML。 - ikegami
@ikegami 没错。我的意思是说,我没有看到MooseX::Storage::Format下的其他模块。 - zdim
在使用MooseX::Storage时需要考虑的一件事情是,当你将对象存储在键/值存储中(例如,在电子商务应用程序中保留产品对象),并且你有许多不同的子类用于不同的产品类型时,你必须在应用程序的某个地方加载所有这些子类,因为MooseX::Storage不能为你完成这项工作。当然,你可以教它如何做到这一点,但更容易的方法是在你的主应用程序类中加载所有这些类。 - simbabque
如果我能得到报酬来编写它就好了。 - Blaise Pascal
2个回答

4
MooseX::Storage使用MooseX::Storage::Format::JSONrole将数据序列化为JSON,这是一个很好的示例,可以用来插入其他格式。我没有看到任何与XML串行化相关的roles,但编写自己的roles非常容易,并且该模块提供了一个钩子。

这个简单的示例展示了如何编写一个role并在类中使用它。一个 role 是一个类似包的类,它永远不会被单独实例化,而是被其他类吸收。它的目的是提供可以轻松“插入”和多次使用的功能。最后展示了如何将新的 role 钩入 MooseX::Storage 中,以便在您的类中使用它。

它使用XML::Dumper本身进行序列化,大多数情况下,它只是作为自定义代码的占位符(如果需要)。

Point.pm

package Point;    

use Moose;

use overload  q("") => sub { 
    my $self = shift; 
    return '(' . $self->x . ', ' . $self->y . ')' 
};  

has 'x' => (is => 'rw', isa => 'Int', required => 1, default => 0); 
has 'y' => (is => 'rw', isa => 'Int', required => 1, default => 0); 

with 'SerializeXML';

sub BUILD { print "Created a Point $_[0]\n" }

__PACKAGE__->meta->make_immutable;    
1;

这里唯一明确的声明是这行代码:with 'SerializeXML'; SerializeXML.pm
package SerializeXML;

use Moose::Role;    
use XML::Dumper;

sub to_xml {
    my ($self) = shift;
    return XML::Dumper->new->pl2xml($self);  # or use custom code
}

sub from_xml {
    my ($self, $xml) = @_; 
    return XML::Dumper->new->xml2pl($xml);
}
    
no Moose::Role;
1;

XML 构建对象应通过 new 或类方法完成。 主要的
use warnings;
use strict;

use Point;

my $pt = Point->new(x => 10, y => 12);

my $obj_xml = $pt->to_xml;
print "$obj_xml\n";

my $obj = $pt->from_xml($obj_xml);
print "Object via role: $obj\n";

这会打印输出

Created a Point (10, 12)
<perldata>
 <hashref blessed_package="Point" memory_address="0x1691438">
  <item key="x">10</item>
  <item key="y">12</item>
 </hashref>
</perldata>
Object via role: (10, 12)

可以添加写入和从文件加载的方法。但现在您有一个准备好的角色,可以连接到 MooseX::Storage 中,如下所示。
我不知道也没有测试 XML::DumperMoose 中的表现如何。请进行测试,如果不能满足您的需求,则将其调用更换为自己编写的代码。
如果需要,剩下的步骤是将其集成到 MooseX::Storage 中。
在上述代码中,有两个必要的小变化。在 Point 中使用角色。
use MooseX::Storage;

with Storage(format => '=SerializeXML', io => 'File');

to_xmlfrom_xml重命名为freezethaw(或添加相同代码的新函数)。

然后,您可以在main中使用storeload来写入$file并从其中加载。

$pt->store($file);
my $pt_new = Point->load($file);

=PackageName语法是用于除MooseX::Storage::Format::以外的命名空间前缀。

关于角色,请参见Moose::Manual::RolesMoose::Cookbook::Roles::命名空间(示例)。


这是一份非常好的指南。如果特别需要XML,我们可以假设操作者对XML已经很熟悉了,因此,可能 XML::Compile 会是一个替代选择,而不是使用XML::Dumper。如果他们编写一个实际的XML模式并将其与数据一起输入给XML :: Compile,甚至可以轻松地从外部源接受数据以直接创建对象,只需提供架构即可。 - simbabque
1
@simbabque 谢谢。这只是基础内容。我不想涉及XML处理,因为那是另一个问题。你提供的建议很好。也许OP应该单独提出有关XML的问题,并描述他们正在做什么以及为什么选择该格式。 - zdim
我正在处理遗留代码/遗留数据,所以我没有选择XML格式,只是从几十年前做出这个决定的人那里继承了它。不幸的是,这意味着XML::Dumper不能使用,因为它无法转储正确的格式。现有的MooseX::Storage::Format模块基本上封装了现有的转储程序,如XML::Dumper,但不提供对格式的任何控制。这不是我需要的。 - Blaise Pascal
@BlaisePascal 等一下...在上面的代码中,您可以插入任何想要的XML处理方式。(例如,如果它们有效,则使用您/他们现有的库。) 它为您提供了切换到Moose的框架,这就是我理解的您所询问的内容。这就是为什么我没有涉及XML--我使用XML::Dumper作为特定XML处理细节的占位符。我是否误解了问题? - zdim
@BlaisePascal 我所知道的,目前没有现成的"MooseX::Storage::Format"模块适用于XML。但整个"MooseX::Storage"都是这样编写的,以便轻松地为任何所需格式添加"roles",这就是我上面想要展示的内容。然后,您可以编写/使用适合您特定目的的代码。再次强调,我正在遵循"想要转换为基于Moose"的原则--您可以添加一个角色,使用现有的代码(如果它有效)。 - zdim

2
所以,MooseX::Storage没有XML存储格式的一个原因是,正如你发现的那样,大多数人都有需要写入的遗留XML格式。XML和Perl实际上具有非常不同的数据表示方式,找到正确的翻译方法并不是可以自动完成的事情。
你不会找到一个“现成”的选项。正如simbabque在评论中提到的,如果您拥有或可以轻松构建数据的模式,则XML::CompileXML::Pastor可能适合您(XML::Compile维护得更好)。如果您愿意做一些苦力活,则XML::Toolkit旨在将示例文档转换为一系列Moose类,然后稍后重新序列化。但是,我已经很长时间没有接触XML::Toolkit了,所以它运行所需的内容可能会有所不同。
我认为最简单的解决方案是您已经拥有的手工构建的toXML方法。Moose并不会阻止您这样做,实际上还提供了一堆工具来帮助您确定如何使其更易于维护。查看MooseX::Storage本身的实现,以找到一个良好的前进道路。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接