How do I serialize Moose objects to XML?

不打扰是莪最后的温柔 提交于 2019-12-23 20:51:39

问题


I have a bunch of legacy modules I want to convert to being Moose-based. The modules currently have "toXML" methods, which are hand-coded using XML::LibXML.

Is there a module or technique for serializing Moose objects to XML?

I have looked at MooseX::Storage, but that handles JSON, YAML, and Storage, not XML. A google search for Moose and XML yields lots of references to XML::Rabbit, which seems to be good for parsing XML into Moose classes, but there's not a lot out there for taking Moose objects and serializing them to XML.

The 6-year-old thread at http://grokbase.com/t/perl/moose/11akp809sr/java-annotation-net-attributes-in-moose is extremely close to what I want to do, but there doesn't seem to be any followup on it.


回答1:


The MooseX::Storage serializes data in JSON by using MooseX::Storage::Format::JSON role, which is a good example for how to plug in other formats. I cannot see any roles for XML serialization, but it is easy to write your own and the module provides a hook for it.

This minimal example shows how to write a role and consume (use) it in a class. A role is a class-like package which never gets instantiated on its own but is rather absorbed by classes that use it. It can be used by multiple classes. At the end it is shown how to hook the new role into MooseX::Storage and thus use that in your class.

It uses XML::Dumper for serialization itself, mostly as a placeholder for custom code (if needed).

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;

The only specific statement here is the line 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;

The construction of an object from XML should be done via new, and/or as a class method.

main

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";

This prints

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)

Methods for writing to and loading from a file can be added. But now you have a ready role which can be hooked to MooseX::Storage, as shown below.

I don't know nor have tested how well XML::Dumper works with Moose. Please test and if it doesn't cut it for your needs swap calls to it with your own code that does what you need.


The remaining step is to integrate this in MooseX::Storage, if desired.

There are two necessary small changes to make in the above code. Use role in Point as

use MooseX::Storage;

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

and rename to_xml and from_xml to freeze and thaw (or add these, with same code).

Then you can use store and load in main in order to write to $file and load from it

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

The syntax =PackageName is for a namespace prefix other than MooseX::Storage::Format::

For roles see Moose::Manual::Roles and Moose::Cookbook::Roles:: namespace (examples).




回答2:


So one of the reasons why MooseX::Storage doesn't have a XML storage format is that as you've discovered, most people have a legacy format for XML that they need to write to. XML and Perl actually have very different ways of representing data and figuring that out the right way to translate between the two isn't actually something you can do automatically.

You're not going to find an "off the shelf" option per-se. As simbabque mentions in a comment if you have or can easily build a Schema for your data then XML::Compile or 'XML::Pastormight work for you (XML::Compileis better maintained). If you're willing to do some grunt workXML::Toolkitis designed to translate an example document into a series of Moose classes that it can then later re-serialize. However I haven't touchedXML::Toolkit` in a long time so YMMV on what it needs to get running.

I think that ultimately you'll find that the simplest solution is the one you already have, hand-built toXML methods. Moose doesn't stop you from doing that, and in fact gives you a bunch of tools to figure out how to make it more maintainable. Look at how MooseX::Storage itself is implemented to see a good path forward.



来源:https://stackoverflow.com/questions/42464465/how-do-i-serialize-moose-objects-to-xml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!