Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Perl Misc (http://www.velocityreviews.com/forums/f67-perl-misc.html)
-   -   Want true instantiated objects from XML (http://www.velocityreviews.com/forums/t908628-want-true-instantiated-objects-from-xml.html)

/usr/ceo 10-12-2008 09:01 PM

Want true instantiated objects from XML
 
I've had a need for this at points in the past, but was always able to
code around it (and still could even now), but I'd really like to be
able to do this, and I can't find anything out there that does this
exactly as I want. (Which tends to make me believe what I want
wouldn't be as immediately useful as maybe I would think it to be,
but...?!)

Given an object defined as this:

package Person;

use strict;
use warnings qw( all );

sub new {
my $proto = shift;
my $class = ref $proto || $proto;
my %attrs = @_;
my $self = {};

# Nevermind the error checking for attributes right now.

$self->{__name} = $attrs{name};
$self->{__age} = $attrs{age};

bless $class, $self;

return $self;
}

# RW attributes.

sub name { $s = shift; $s->{__name} = shift if @_; return $s-
>{__name} }

sub age { $s = shift; $s->{__age} = shift if @_; return $s->{__age} }

# Methods.

sub sayName { print "My name is: " . shift->{__name} . "\n" }
sub sayAge { print "I am " . shift->{__age} . " years old.\n" }

1;

I want to be able to read the following XML and create instances of
Person from each instance in the XML:

<xml>
<People>
<Person name="John Doe" age="22" />
<Person name="Jane Doe" age="23" />
<Person name="Maxx Doogan" age="10" />
</People>
</xml>

So I get an array of Person objects which I can then write:

my @people; # Hold the array of Person object created from the XML
above.

for my $person (@people) {
$person->sayName();
$person->sayAge();
}

I've looked through SOAP::Lite (and SOAP::Serialize and
SOAP::Deserialize). I'm a fairly frequent user of XML::Simple, but
Simple doesn't do the above (AFAIK). SURELY *something* like this is
"out there" (read "CPAN") but I can't seem to find it; only things
close to it (like SOAP::SOM objects that require an xpath of sorts and
my methods are still not available through an instantiated method of
just the data [object attributes] in XML.)

Thanks!
/usr/ceo

Zed Pobre 10-12-2008 11:17 PM

Re: Want true instantiated objects from XML
 
/usr/ceo <newsbot@cox.net> wrote:
> I've looked through SOAP::Lite (and SOAP::Serialize and
> SOAP::Deserialize). I'm a fairly frequent user of XML::Simple, but
> Simple doesn't do the above (AFAIK). SURELY *something* like this is
> "out there" (read "CPAN") but I can't seem to find it; only things
> close to it (like SOAP::SOM objects that require an xpath of sorts and
> my methods are still not available through an instantiated method of
> just the data [object attributes] in XML.)


I would do it with XML::Twig, myself, though there are other options.

#!/usr/bin/perl
use strict; use warnings
use Person;
use XML::Twig;

my $twig = XML::Twig->new();
$twig->parse(\*DATA);

my ($name, $age);
my $person;
my @personslist;
my @xmlpersons = $twig->root->descendants('Persons');

foreach my $element (@xmlpersons)
{
$name = $element->att('name');
$age = $element->att('age');
$person = Person->new('name' => $name, 'age' => $age);
push(@personslist,$person);
}

__DATA__
<xml>
<People>
<Person name="John Doe" age="22" />
<Person name="Jane Doe" age="23" />
<Person name="Maxx Doogan" age="10" />
</People>
</xml>

##########

You're looking for something like that?

--
Zed Pobre <zed@resonant.org> a.k.a. Zed Pobre <zed@debian.org>
PGP key and fingerprint available on finger; encrypted mail welcomed.

sln@netherlands.com 10-12-2008 11:46 PM

Re: Want true instantiated objects from XML
 
On Sun, 12 Oct 2008 14:01:14 -0700 (PDT), "/usr/ceo" <newsbot@cox.net> wrote:

>I've had a need for this at points in the past, but was always able to
>code around it (and still could even now), but I'd really like to be
>able to do this, and I can't find anything out there that does this
>exactly as I want. (Which tends to make me believe what I want
>wouldn't be as immediately useful as maybe I would think it to be,
>but...?!)
>
>Given an object defined as this:
>
>package Person;
>
>use strict;
>use warnings qw( all );
>
>sub new {
> my $proto = shift;
> my $class = ref $proto || $proto;
> my %attrs = @_;
> my $self = {};
>
> # Nevermind the error checking for attributes right now.
>
> $self->{__name} = $attrs{name};
> $self->{__age} = $attrs{age};
>
> bless $class, $self;
>
> return $self;
>}
>
># RW attributes.
>
>sub name { $s = shift; $s->{__name} = shift if @_; return $s-
>>{__name} }

>sub age { $s = shift; $s->{__age} = shift if @_; return $s->{__age} }
>
># Methods.
>
>sub sayName { print "My name is: " . shift->{__name} . "\n" }
>sub sayAge { print "I am " . shift->{__age} . " years old.\n" }
>
>1;
>

The above is all very impressive. What do you want to do?

>I want to be able to read the following XML and create instances of
>Person from each instance in the XML:
>
><xml>
><People>
> <Person name="John Doe" age="22" />
> <Person name="Jane Doe" age="23" />
> <Person name="Maxx Doogan" age="10" />
></People>
></xml>
>


So XML parsing is holding you up?

>So I get an array of Person objects which I can then write:
>
>my @people; # Hold the array of Person object created from the XML
>above.
>
>for my $person (@people) {
> $person->sayName();
> $person->sayAge();
>}
>
>I've looked through SOAP::Lite (and SOAP::Serialize and
>SOAP::Deserialize). I'm a fairly frequent user of XML::Simple, but
>Simple doesn't do the above (AFAIK). SURELY *something* like this is
>"out there" (read "CPAN") but I can't seem to find it; only things
>close to it (like SOAP::SOM objects that require an xpath of sorts and
>my methods are still not available through an instantiated method of
>just the data [object attributes] in XML.)
>
>Thanks!
>/usr/ceo



rxparse version 2

sln


/usr/ceo 10-13-2008 06:53 AM

Re: Want true instantiated objects from XML
 
On Oct 12, 6:17*pm, Zed Pobre <z...@resonant.org> wrote:
> /usr/ceo <news...@cox.net> wrote:
> > I've looked through SOAP::Lite (and SOAP::Serialize and
> > SOAP::Deserialize). *I'm a fairly frequent user of XML::Simple, but
> > Simple doesn't do the above (AFAIK). *SURELY *something* like this is
> > "out there" (read "CPAN") but I can't seem to find it; only things
> > close to it (like SOAP::SOM objects that require an xpath of sorts and
> > my methods are still not available through an instantiated method of
> > just the data [object attributes] in XML.)

>
> I would do it with XML::Twig, myself, though there are other options.
>
> #!/usr/bin/perl
> use strict; use warnings
> use Person;
> use XML::Twig;
>
> my $twig = XML::Twig->new();
> $twig->parse(\*DATA);
>
> my ($name, $age);
> my $person;
> my @personslist;
> my @xmlpersons = $twig->root->descendants('Persons');
>
> foreach my $element (@xmlpersons)
> {
> * * $name = $element->att('name');
> * * $age = $element->att('age');
> * * $person = Person->new('name' => $name, 'age' => $age);
> * * push(@personslist,$person);
>
> }
>
> __DATA__
> <xml>
> <People>
> * * <Person name="John Doe" age="22" />
> * * <Person name="Jane Doe" age="23" />
> * * <Person name="Maxx Doogan" age="10" />
> </People>
> </xml>
>
> ##########
>
> You're looking for something like that?


Well that's definitely pretty nice. It's about halfway between what I
want and what I thought I was going to have to do, which was close to
what you wrote -- I just hadn't looked at XML::Twig. This is close
enough to what I want without providing a schema upfront (which is why
I think it would be a little difficult to write something smart enough
to marshall to and from XML since XML is for all intents and purposes,
free-format.)

I think the XML::Twig hit will be helpful and I'll probably do that.

Thanks!
/usr/ceo

/usr/ceo 10-13-2008 06:57 AM

Re: Want true instantiated objects from XML
 
On Oct 12, 6:46*pm, s...@netherlands.com wrote:
> On Sun, 12 Oct 2008 14:01:14 -0700 (PDT), "/usr/ceo" <news...@cox.net> wrote:
> >I've had a need for this at points in the past, but was always able to
> >code around it (and still could even now), but I'd really like to be
> >able to do this, and I can't find anything out there that does this
> >exactly as I want. *(Which tends to make me believe what I want
> >wouldn't be as immediately useful as maybe I would think it to be,
> >but...?!)

>
> >Given an object defined as this:

>
> >package Person;

>
> >use strict;
> >use warnings qw( all );

>
> >sub new {
> > * my $proto = shift;
> > * my $class = ref $proto || $proto;
> > * my %attrs = @_;
> > * my $self = {};

>
> > * # Nevermind the error checking for attributes right now.

>
> > * $self->{__name} = $attrs{name};
> > * $self->{__age} = $attrs{age};

>
> > * bless $class, $self;

>
> > * return $self;
> >}

>
> ># RW attributes.

>
> >sub name { $s = shift; $s->{__name} = shift if @_; return $s-
> >>{__name} }

> >sub age { $s = shift; $s->{__age} = shift if @_; return $s->{__age} }

>
> ># Methods.

>
> >sub sayName { print "My name is: " . shift->{__name} . "\n" }
> >sub sayAge { print "I am " . shift->{__age} . " years old.\n" }

>
> >1;

>
> The above is all very impressive. What do you want to do?
>
> >I want to be able to read the following XML and create instances of
> >Person from each instance in the XML:

>
> ><xml>
> ><People>
> > * <Person name="John Doe" age="22" />
> > * <Person name="Jane Doe" age="23" />
> > * <Person name="Maxx Doogan" age="10" />
> ></People>
> ></xml>

>
> So XML parsing is holding you up?


No, I can parse most of the XML I need with XML::Simple. The point
is, I don't really want the hashed structure that XML::Simple
provides, even though I can munge the parsing with ForceGroup and
other options. So no, the parsing isn't the issue. I want more of an
XML "freeze / unfreeze" or serialize / deserialize (marshalling)
solution. (Marshalling and s/d aren't always the same I realize...)

>
>
> >So I get an array of Person objects which I can then write:

>
> >my @people; # Hold the array of Person object created from the XML
> >above.

>
> >for my $person (@people) {
> > * $person->sayName();
> > * $person->sayAge();
> >}

>
> >I've looked through SOAP::Lite (and SOAP::Serialize and
> >SOAP::Deserialize). *I'm a fairly frequent user of XML::Simple, but
> >Simple doesn't do the above (AFAIK). *SURELY *something* like this is
> >"out there" (read "CPAN") but I can't seem to find it; only things
> >close to it (like SOAP::SOM objects that require an xpath of sorts and
> >my methods are still not available through an instantiated method of
> >just the data [object attributes] in XML.)

>
> >Thanks!
> >/usr/ceo

>
> rxparse version 2


I'll check that out as well, but the solution Zed offered was closer
to what I was looking for. Close enough.

Thanks!
/usr/ceo

/usr/ceo 10-13-2008 03:10 PM

Re: Want true instantiated objects from XML
 
On Oct 13, 1:57*am, "/usr/ceo" <news...@cox.net> wrote:
> On Oct 12, 6:46*pm, s...@netherlands.com wrote:
>
>
>
> > On Sun, 12 Oct 2008 14:01:14 -0700 (PDT), "/usr/ceo" <news...@cox.net> wrote:
> > >I've had a need for this at points in the past, but was always able to
> > >code around it (and still could even now), but I'd really like to be
> > >able to do this, and I can't find anything out there that does this
> > >exactly as I want. *(Which tends to make me believe what I want
> > >wouldn't be as immediately useful as maybe I would think it to be,
> > >but...?!)

>
> > >Given an object defined as this:

>
> > >package Person;

>
> > >use strict;
> > >use warnings qw( all );

>
> > >sub new {
> > > * my $proto = shift;
> > > * my $class = ref $proto || $proto;
> > > * my %attrs = @_;
> > > * my $self = {};

>
> > > * # Nevermind the error checking for attributes right now.

>
> > > * $self->{__name} = $attrs{name};
> > > * $self->{__age} = $attrs{age};

>
> > > * bless $class, $self;

>
> > > * return $self;
> > >}

>
> > ># RW attributes.

>
> > >sub name { $s = shift; $s->{__name} = shift if @_; return $s-
> > >>{__name} }
> > >sub age { $s = shift; $s->{__age} = shift if @_; return $s->{__age} }

>
> > ># Methods.

>
> > >sub sayName { print "My name is: " . shift->{__name} . "\n" }
> > >sub sayAge { print "I am " . shift->{__age} . " years old.\n" }

>
> > >1;

>
> > The above is all very impressive. What do you want to do?

>
> > >I want to be able to read the following XML and create instances of
> > >Person from each instance in the XML:

>
> > ><xml>
> > ><People>
> > > * <Person name="John Doe" age="22" />
> > > * <Person name="Jane Doe" age="23" />
> > > * <Person name="Maxx Doogan" age="10" />
> > ></People>
> > ></xml>

>
> > So XML parsing is holding you up?

>
> No, I can parse most of the XML I need with XML::Simple. *The point
> is, I don't really want the hashed structure that XML::Simple
> provides, even though I can munge the parsing with ForceGroup and
> other options. *So no, the parsing isn't the issue. *I want more of an
> XML "freeze / unfreeze" or serialize / deserialize (marshalling)
> solution. *(Marshalling and s/d aren't always the same I realize...)
>
>
>
>
>
> > >So I get an array of Person objects which I can then write:

>
> > >my @people; # Hold the array of Person object created from the XML
> > >above.

>
> > >for my $person (@people) {
> > > * $person->sayName();
> > > * $person->sayAge();
> > >}

>
> > >I've looked through SOAP::Lite (and SOAP::Serialize and
> > >SOAP::Deserialize). *I'm a fairly frequent user of XML::Simple, but
> > >Simple doesn't do the above (AFAIK). *SURELY *something* like this is
> > >"out there" (read "CPAN") but I can't seem to find it; only things
> > >close to it (like SOAP::SOM objects that require an xpath of sorts and
> > >my methods are still not available through an instantiated method of
> > >just the data [object attributes] in XML.)

>
> > >Thanks!
> > >/usr/ceo

>
> > rxparse version 2

>
> I'll check that out as well, but the solution Zed offered was closer
> to what I was looking for. *Close enough.
>
> Thanks!
> /usr/ceo


For those of you following along at home, there were some minor errors
with the code I typed in off the top of my head for my example.
blessing into $class is wrong. Using "strict" the $s variable in my
accessors needed to be "my"'d. I hate it when I read a book or try to
pull something from Usenet and it doesn't work due to unchecked errors
on the part of the author! :-) :-(

Here is the final XML::Twig solution, taking Zed's XML::Twig solution,
adding in the Person package (just inline in this case) and correcting
for a few errors (and making a few ticky-tack "the way I do things"
changes to Zed's example which was fine as it was):

#!/usr/bin/perl

use strict;
use warnings qw( all );

package Person;

use strict;
use warnings qw( all );

sub new {
my $proto = shift;
my $class = ref $proto || $proto;
my %attrs = @_;
my $self = {};

# Nevermind the error checking for attributes right now.

$self->{__name} = $attrs{name};
$self->{__age} = $attrs{age};

bless $self, $class;
return $self;
}

# RW attributes.

sub name { my $s = shift; $s->{__name} = shift if @_; return $s-
>{__name} }

sub age { my $s = shift; $s->{__age} = shift if @_; return $s-
>{__age} }


# Methods.

sub sayName { print "My name is: " . shift->{__name} . "\n" }
sub sayAge { print "I am " . shift->{__age} . " years old.\n" }

package main;

use XML::Twig;

my $twig = XML::Twig->new();
$twig->parse( \*DATA );

my @people;
my @xmlpersons = $twig->root->descendants( 'Person' );

for my $element (@xmlpersons) {
my $name = $element->att( 'name' );
my $age = $element->att( 'age' );
my $person = Person->new( name => $name, age => $age );
push @people, $person;
}

for my $person (@people) {
print "-" x 10 . "\n";
$person->sayName();
$person->sayAge();
}

__DATA__
<xml>
<People>
<Person name="John Doe" age="22" />
<Person name="Jane Doe" age="23" />
<Person name="Maxx Doogan" age="10" />
</People>
</xml>

Grüss!
/usr/ceo


All times are GMT. The time now is 01:36 PM.

Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.