Hi there,
I'm trying to parse an XML file into an object structure — my own object structure. I'm bewildered by the range of XML parsers and somewhat confused by the fact that none of them seem to do what I want — although this may be because all of the examples of their use that I've found are too simple to illustrate the full capabilities of the various parsers.
What I was expecting was that there'd be a parser which would allow me to create a range of subclasses of its Element class, and that these subclasses would have their start_tag and end_tag methods called as an XML document was being parsed — the start_tag acting as a constructor, and the end_tag checking the parsed list of contents objects and actually storing them in whatever way it wanted to.
I've not found something which seems to do this — but one of the Perl XML parsers must, I just can't find which!
Wishful code attached. The first part just uses XML::Parser's Objects mode, which is the closest approximation of what I want that I found, but it's still using its own structures to store the data and doesn't make callbacks against the classes it's blessing the data into. The second part sketches an example pair of classes in the style that I was expecting some parser or other to support — XML::Parser doesn't call their _tag methods though, of course.
Any suggestions?
Update 0: As I say below in response to tlm's question, I've discovered a name for what I'm after: XML Data Binding. Here's an article on the subject. It's Java-centric though, and doesn't offer any Perl answers...
Update 1: have written an extension to XML::Parser to do the job. See below.
Conrad
#!/usr/bin/perl use strict; use warnings; use XML::Parser; use Data::Dumper; my $text = '<container><thing>hi</thing><thing>there</thing></containe +r>'; my $parser = new XML::Parser(Style => 'Objects', Pkg => 'MyPkg'); my $object = $parser->parse($text)->[0]; print Dumper($object); { package MyPkg::container; # use base 'XML::Element'; # Or something like that? # Constructor method, nothing exciting happening here so # it's redundant but just to show I could have one... sub start_tag { my ($class, $container) = shift; # The parser should use start_tag's return value when # returning this parsed object to anything containing it (or # the caller if this is the root object). bless {}, $class } sub end_tag { # Should get contained objects as values # Check accumulated contents and store values in my hash - # here I'm expecting only a list of <thing>s... my ($self, @contents) = @_; die "Non-thing (" . ref $_ . ") in container!" for grep ! $_->isa('MyPkg::thing'), @contents; $self->{THINGS} = \@contents; } sub myMethod { # Execute stuff using parsed objects } } { package MyPkg::thing; # use base 'XML::Element'; # Or something like that? sub end_tag { # Should get contained objects as values # Check accumulated contents and store values in my hash - # here I'm expecting only plain text in the form of scalars. my ($self, @contents) = @_; die "Non-scalar (" . ref $_ . ") in thing!" for grep ref $_, @contents; $self->{DATA} = join('', @contents); } }
In reply to Parse XML to my own objects? (aka XML Data Binding) by conrad
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |