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

Hi Monks, I have an XML file as shown below. As you can see, it contains 2 different types of tables - Phones and Subs. I have trouble reading/printing them out. I keep getting the error "Out of memory!". Just a note, when I manually remove the "<anon>" tags, I can use the same code to read/print the data. Thanks.
my $xml = new XML::Simple; my $data = $xml->XMLin("testing.xml"); my $e; foreach $e (@{$data->{Phones}}) { print "\n$e->{Manufacturer}"; print "\n$e->{Model}"; print "\n$e->{Version}"; print "\n$e->{Count}"; print "\n==========================="; }
<?xml version='1.0'?> <terminalversioncount> <anon> <Phones> <Count>2</Count> <Manufacturer>Company X</Manufacturer> <Model>P90</Model> <Version>RM-194</Version> </Phones> </anon> <anon> <Phones> <Count>7</Count> <Manufacturer>Rocket Inc</Manufacturer> <Model>PlugX</Model> <Version>1.01</Version> </Phones> </anon> <anon> <Subs> <MNO_ID>7222</MNO_ID> <NAME></NAME> <PNAME></PNAME> <PURCHASE_CODE>7224</PURCHASE_CODE> </Subs> </anon> <anon> <Subs> <MNO_ID>7223</MNO_ID> <NAME></NAME> <PNAME></PNAME> <PURCHASE_CODE>7224</PURCHASE_CODE> </Subs> </anon> </terminalversioncount>

Replies are listed 'Best First'.
Re: XML::Simple - storing/retrieving 2 tables into 1 XML file
by GrandFather (Saint) on Sep 11, 2008 at 10:38 UTC

    There is a nasty trap waiting for you in:

    my $e; foreach $e (...)

    The lexical $e you declare outside the loop is not the same entity as the $e you use as a loop variable. In particular, the lexical $e is not set to the value of the loop variable $e following the last iteration of the loop. It is much better to write:

    foreach my $e (...)

    to avoid misunderstandings. Note that the loop variable is an alias for each item that is iterated over. That means that if you alter the contents of the loop variable you are altering the contents of the item the loop variable is aliased to. Consider:

    my @data = 1 .. 10; for my $item (@data) { $item *= 5; } print "@data\n";

    prints: 5 10 15 20 25 30 35 40 45 50


    Perl reduces RSI - it saves typing
Re: XML::Simple - storing/retrieving 2 tables into 1 XML file
by lamp (Chaplain) on Sep 11, 2008 at 10:06 UTC
    As it mentioned in the XML::Simple documentation, the '<anon>' tag is used to form anonymous arrays. You can use the following method for retriving the values if you use '<anon>' tag.
    #!/usr/bin/perl -w use strict; use XML::Simple; my $xml = new XML::Simple; my $data = $xml->XMLin("testing.xml"); for (my $i=0;$i<$#{$data};$i++) { if($data->[$i]->{Phones}) { print "\n$data->[$i]->{Phones}->{Manufacturer}"; print "\n$data->[$i]->{Phones}->{Model}"; print "\n$data->[$i]->{Phones}->{Version}"; print "\n$data->[$i]->{Phones}->{Count}"; print "\n==========================="; } }
      for (my $i=0;$i<$#{$data};$i++) { if($data->[$i]->{Phones}) { print "\n$data->[$i]->{Phones}->{Manufacturer}"; ... } }

      is much better written:

      for my $item (@$data) { next unless $item->{Phones}; print "\n$item->{Phones}->{Manufacturer}"; ... }

      Perl reduces RSI - it saves typing
      Hi folks, thanks for the advice. Finally got it working now!
Re: XML::Simple - storing/retrieving 2 tables into 1 XML file
by maspalio (Scribe) on Sep 11, 2008 at 10:07 UTC
    It seems like your structure is not exactly the way you are expecting it to be. You'll want to use a module like Data::Dumper::Simple to check it out.

    This said, just change:

      foreach $e (@{$data->{Phones}})
    

    into:

      foreach (@$data)
      {
              my $e = $_->{Phones};
    

    and the magick occurs ;^)

    HTH.

Re: XML::Simple - storing/retrieving 2 tables into 1 XML file
by i-robot (Initiate) on Sep 11, 2008 at 14:14 UTC
    use strict; use XML::Simple; my $xml = new XML::Simple; my $data = $xml->XMLin("testing.xml"); my $e; foreach $e (@{$data->{Phones}}) { print "\n$e->{Manufacturer}"; print "\n$e->{Model}"; print "\n$e->{Version}"; print "\n$e->{Count}"; print "\n==========================="; }
    I try this code on testing.xml, it says : Not a HASH reference at 710565.pl line 7.
    Then I remove the <anon> and </anon>, it runs ok. Quite bizarre.
Re: XML::Simple - storing/retrieving 2 tables into 1 XML file
by Anonymous Monk on Sep 11, 2008 at 10:09 UTC
    Why aren't you taking advice from your previous nodes. Pseudo-hashes are deprecated , so stop using them.
Re: XML::Simple - storing/retrieving 2 tables into 1 XML file
by i-robot (Initiate) on Sep 11, 2008 at 15:05 UTC
    use XML::Simple; my $xml = new XML::Simple; my $data = $xml->XMLin("testing.xml"); foreach my $e (@{$data}) { my $p; if ($p=$e->{Phones}) { print "\n$p->{Manufacturer}"; print "\n$p->{Model}"; print "\n$p->{Version}"; print "\n$p->{Count}"; print "\n==========================="; } }
    It works.
      Not surprised. As someone already suggested use Data::Dumper to understand the differences in the data structures ($data). The 2 versions of the XML document are not same, so it is only natural that the data structures generated will not be the same either.