osprofi has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I am trying to extract xml data with the xml::parser module and to store them into an array of hashes for further processing - tag extraction works fine, but storing the tag values into the array of hashes is the issue.

May be you can assist me here and what I am doing wrong:

xml data file:

<Catalog> <Category> <Name>Arts &amp; Entertainment</Name> <Site> <Id>...</Id> <Title>...</Title> </Site> <Site> <Id>...</Id> <Title>...</Title> </Site> </Category> <Catalog>

perl prg:

$parser = XML::Parser->new(Handlers => {Start => \&start, Char => \&char, End => \&end} ); sub start{ my ($p, $elt, %atts) = @_; if ($elt eq 'Site') { %site = (); #this is the hash per one site } if ($elt eq 'Id') { $tag_id = 1; } if ($elt eq 'Title') { $tag_title = 1; } } sub char { my ($p, $str) = @_; if ($tag_id eq 1) { $id = trim($str); } if ($tag_title eq 1) { $title = trim($str); } } sub end{ my ($p, $elt) = @_; if ($tag_id eq 1 and $elt eq 'Id') { $site{ $id } = $id; $tag_id = 0; } if ($tag_title eq 1 and $elt eq 'Title') { $site{ $title } = $title; $tag_title = 0; } if ($elt eq 'Site') { push(@cb, %site); print %site . "\n"; } } # if I want to process now the @cb then no data are inside.
Thanks for assistance, Peter

Replies are listed 'Best First'.
Re: parse xml and store data in array of hashesh
by Anonymous Monk on Jul 22, 2011 at 07:04 UTC
    To build an array of hashes , you need to store, hashrefs in the array, like this
    #!/usr/bin/perl -- use strict; use warnings; my %foo = 1..2; my @bar = %foo; push @bar, \%foo; use Data::Dumper; print Dumper( \@bar ); __END__ $VAR1 = [ '1', 2, { '1' => 2 } ];

    See the \ operator takes a reference, to an array (\@array), to a hash (\%hash), to a scalar (\$scalar)

    See Tutorials: References quick reference

      Hi, thanks very much for quick repl; but even with stored hash references in sub _end; the array @cb does not have data when trying to print them Greetings, Peter
        Hi, you're welcome :)

        You made it very easy as your question was very effective (How do I post a question effectively? , How do I compose an effective node title?).

        Here is a similar approach using XML::Twig

        #!/usr/bin/perl -- #~ 2011-07-23-08:42:20+0000 by Anonymous Monk #~ perltidy -csc -otr -opr -ce -nibc -i=4 use strict; use warnings; use autodie; # dies if open/close... fail use Data::Dumper; use XML::Twig; Main( @ARGV ); exit( 0 ); sub Main { Demo(); } sub NotDemoMeaningfulName { my ($xml) = @_; my @data; my %site; my $t = XML::Twig->new( twig_handlers => { '//Site' => sub { warn $_->path; push @data, {%site} if %site; %site = (); $_->purge; # free memory }, '//Site/Id' => sub { warn $_->path; $site{Id} = $_->trimmed_text; }, '//Site/Title' => sub { warn $_->path; $site{Title} = $_->trimmed_text; }, }, ); $t->xparse($xml); $t->purge; return \@data; } ## end sub NotDemoMeaningfulName sub Demo { my $ref = NotDemoMeaningfulName( DemoData() ); print Dumper($ref); } sub DemoData { #~ http://perlmonks.com/?abspart=1;displaytype=displaycode;node_id=916 +054;part=1 my $xml = <<'__XML__'; <Catalog> <Category> <Name>Arts &amp; Entertainment</Name> <Site> <Id>01-id...</Id> <Title>01-title...</Title> </Site> <Site> <Id>02-id...</Id> <Title>02-title...</Title> </Site> </Category> </Catalog> __XML__ return $xml; } ## end sub DemoData __END__ $ perl xml.twig.916054.pl /Catalog/Category/Site/Id at xml.twig.916054.pl line 30. /Catalog/Category/Site/Title at xml.twig.916054.pl line 34. /Catalog/Category/Site at xml.twig.916054.pl line 24. /Catalog/Category/Site/Id at xml.twig.916054.pl line 30. /Catalog/Category/Site/Title at xml.twig.916054.pl line 34. /Catalog/Category/Site at xml.twig.916054.pl line 24. $VAR1 = [ { 'Id' => '01-id...', 'Title' => '01-title...' }, { 'Id' => '02-id...', 'Title' => '02-title...' } ];
Re: parse xml and store data in array of hashesh
by metaperl (Curate) on Jul 22, 2011 at 16:41 UTC
Re: parse xml and store data in array of hashesh
by Jenda (Abbot) on Jul 25, 2011 at 21:39 UTC

    XML::Parser is too low-level. Have a look at XML::Rules.

    Also evaluating a hash in string context doesn't give you the contents of the hash. It returns two numbers separated by slash whose meaning is most probably the least of your worries. Pushing a hash into an array also doesn't do what you seem to think.

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.