Loading ...
Sorry, an error occurred while loading the content.

XML parsing

Expand Messages
  • greg.hering@bench.com
    Hey! Request for XML (really probably basic perl datatypes) understanding. This has the short data, short code and short output, but altogether it gets long.
    Message 1 of 3 , Jun 30, 2003
    • 0 Attachment
      Hey! Request for XML (really probably basic perl datatypes) understanding.

      This has the short data, short code and short output, but altogether it gets long. I'll ask the question first.

      I'm parsing a file formatted as XML, using XML::Simple, that tells the names of directories on a host.

      If the host has one directory, then the type returned in my code is a HASH. If it has two then the type is ARRAY.

      In trying to figure out the data structure, I used Dumper. My code says the loop is an array of arrays (iterating with a foreach) but it looks like an array of hashes and I can't figure out how to access it in a loop.

      In the code below, you can see I thought the control variable in the 'foreach' would iterate over the elements of the array and return me a hash. I can hard-code '$config->{host}->{dir}[0]->{name}' to get what I want, but I want to understand what is happening well enough to do it in a loop.

      In the loop, $dir says it is an ARRAY (using ref()) but
      print '$dir[0]' . " is $dir[0]"; #error
      is an error, as is
      print "$dir->{name}\n"; #error

      Only
      {dir}[0]->{name} # works

      is valid, but that's not suitable for a loop.

      Here's my sample data file:

      <?xml version='1.0' encoding='ISO-8859-1' ?>
      <!DOCTYPE MyHostFormat>
      <configuration>
      <host name="forth">
      <dir name="/export/DATA" /> ## add more dirs here
      <dir name="/export/DATATWO" />
      </host>
      </configuration>


      Here's my test program:

      use XML::Simple qw(:strict);
      use Data::Dumper;
      use strict;

      my $xs = new XML::Simple('keyattr' => 'host', ForceArray => 0);
      my $config = $xs->XMLin("/tmp/hostconfig.xml");

      print Dumper($config);

      #assign a reference part way down - to make life easier.
      my $dirs = $config->{host}->{dir};

      my $type = ref($dirs) || $dirs;

      if ($type eq "HASH") {
      print '$config->{host}->{dir}' . " is a HASH type\n";
      print '$config->{host}->{dir}->{name}' . " and is: $config->{host}->{dir}->{name}\n";
      }

      if ($type eq "ARRAY") {
      print '$config->{host}->{dir}' . " is an ARRAY type\n";

      # would like the size of the array but this doesn't work...
      # print 'size of $config->{host}->{dir}' . " is $#config->{host}->{dir}\n";
      # nor does
      print 'size of $config->{host}->{dir}' . " is $#dirs\n";

      foreach my $dir ($dirs)
      { # dir should be an array of hashes
      my $type = ref($dir);
      printf '$config->{host}->{dir}[?]' . " type is %s\n", $type;
      print "$dir\n";
      # print "$dir->{name}\n"; gives error because $dir isn't a hash.
      }
      }



      --------------- The output with one host directory: ----------------

      > test.pl
      $VAR1 = {
      'host' => {
      'name' => 'forth',
      'dir' => {
      'name' => '/export/DATA'
      }
      }
      };
      $config->{host}->{dir} is a HASH type
      >

      --------------- The output with two host directories: ----------------

      > test.pl
      $VAR1 = {
      'host' => {
      'name' => 'forth',
      'dir' => [
      {
      'name' => '/export/DATA'
      },
      {
      'name' => '/export/DATATWO'
      }
      ]
      }
      };
      $config->{host}->{dir} is an ARRAY type
      $config->{host}->{dir}[?] type is ARRAY
      ARRAY(0x6bcc78)

      If I print the iterator in the foreach loop it says an array is next:
      printf '$config->{host}->{dir}[?]' . " type is %s\n", $type;

      i.e.
      print "$dir\n"; #the control variable from foreach
      says
      ARRAY(0x6bcc78)

      I thought the control variable in the 'foreach' would iterate over the elements of the array and return me a hash.

      If I print this I get the value:
      printf '$config->{host}->{dir}[?]' . " value is %s\n", $config->{host}->{dir}[0]->{name};

      but I can't figure out how to do it in a loop.


      Thanks,

      Greg



      Gregory L. Hering
      (256) 722-6420
      4807 Bradford Dr
      Benchmark Electronics, Inc.
      Huntsville, Al 35805
    • Mark Reed
      If I understand, your only having problems when $type is an array correct? In the case that $type is an array, The array will contain hash references. Each
      Message 2 of 3 , Jun 30, 2003
      • 0 Attachment
        If I understand, your only having problems when $type
        is an array correct?

        In the case that $type is an array, The array will
        contain hash references. Each hash will have a key of
        'name', and a 'value' of the directory.

        I think this is the loop your looking for:

        if ($type eq "ARRAY") {
        foreach my $hash (@$dirs) {
        print "$$hash{name}\n";
        }
        }

        Or:
        if ($type eq "ARRAY") {
        foreach my $hash (@$dirs) {
        foreach my $value ( values %$hash ) {
        print "$value \n";
        }
        }
        }




        --- greg.hering@... wrote:
        > Hey! Request for XML (really probably basic perl
        > datatypes) understanding.
        >
        > This has the short data, short code and short
        > output, but altogether it gets long. I'll ask the
        > question first.
        >
        > I'm parsing a file formatted as XML, using
        > XML::Simple, that tells the names of directories on
        > a host.
        >
        > If the host has one directory, then the type
        > returned in my code is a HASH. If it has two then
        > the type is ARRAY.
        >
        > In trying to figure out the data structure, I used
        > Dumper. My code says the loop is an array of arrays
        > (iterating with a foreach) but it looks like an
        > array of hashes and I can't figure out how to access
        > it in a loop.
        >
        > In the code below, you can see I thought the control
        > variable in the 'foreach' would iterate over the
        > elements of the array and return me a hash. I can
        > hard-code '$config->{host}->{dir}[0]->{name}' to get
        > what I want, but I want to understand what is
        > happening well enough to do it in a loop.
        >
        > In the loop, $dir says it is an ARRAY (using ref())
        > but
        > print '$dir[0]' . " is $dir[0]"; #error
        > is an error, as is
        > print "$dir->{name}\n"; #error
        >
        > Only
        > {dir}[0]->{name} # works
        >
        > is valid, but that's not suitable for a loop.
        >
        > Here's my sample data file:
        >
        > <?xml version='1.0' encoding='ISO-8859-1' ?>
        > <!DOCTYPE MyHostFormat>
        > <configuration>
        > <host name="forth">
        > <dir name="/export/DATA" /> ## add more dirs
        > here
        > <dir name="/export/DATATWO" />
        > </host>
        > </configuration>
        >
        >
        > Here's my test program:
        >
        > use XML::Simple qw(:strict);
        > use Data::Dumper;
        > use strict;
        >
        > my $xs = new XML::Simple('keyattr' => 'host',
        > ForceArray => 0);
        > my $config = $xs->XMLin("/tmp/hostconfig.xml");
        >
        > print Dumper($config);
        >
        > #assign a reference part way down - to make life
        > easier.
        > my $dirs = $config->{host}->{dir};
        >
        > my $type = ref($dirs) || $dirs;
        >
        > if ($type eq "HASH") {
        > print '$config->{host}->{dir}' . " is a HASH
        > type\n";
        > print '$config->{host}->{dir}->{name}' . " and
        > is: $config->{host}->{dir}->{name}\n";
        > }
        >
        > if ($type eq "ARRAY") {
        > print '$config->{host}->{dir}' . " is an ARRAY
        > type\n";
        >
        > # would like the size of the array but this
        > doesn't work...
        > # print 'size of $config->{host}->{dir}' . " is
        > $#config->{host}->{dir}\n";
        > # nor does
        > print 'size of $config->{host}->{dir}' . " is
        > $#dirs\n";
        >
        > foreach my $dir ($dirs)
        > { # dir should be an
        > array of hashes
        > my $type = ref($dir);
        > printf '$config->{host}->{dir}[?]' . " type is
        > %s\n", $type;
        > print "$dir\n";
        > # print "$dir->{name}\n"; gives error because
        > $dir isn't a hash.
        > }
        > }
        >
        >
        >
        > --------------- The output with one host directory:
        > ----------------
        >
        > > test.pl
        > $VAR1 = {
        > 'host' => {
        > 'name' => 'forth',
        > 'dir' => {
        > 'name' =>
        > '/export/DATA'
        > }
        > }
        > };
        > $config->{host}->{dir} is a HASH type
        > >
        >
        > --------------- The output with two host
        > directories: ----------------
        >
        > > test.pl
        > $VAR1 = {
        > 'host' => {
        > 'name' => 'forth',
        > 'dir' => [
        > {
        > 'name' =>
        > '/export/DATA'
        > },
        > {
        > 'name' =>
        > '/export/DATATWO'
        > }
        > ]
        > }
        > };
        > $config->{host}->{dir} is an ARRAY type
        > $config->{host}->{dir}[?] type is ARRAY
        > ARRAY(0x6bcc78)
        >
        > If I print the iterator in the foreach loop it says
        > an array is next:
        > printf '$config->{host}->{dir}[?]' . " type is
        > %s\n", $type;
        >
        > i.e.
        > print "$dir\n"; #the control variable from
        > foreach
        > says
        > ARRAY(0x6bcc78)
        >
        > I thought the control variable in the 'foreach'
        > would iterate over the elements of the array and
        > return me a hash.
        >
        > If I print this I get the value:
        > printf '$config->{host}->{dir}[?]' . " value is
        > %s\n", $config->{host}->{dir}[0]->{name};
        >
        > but I can't figure out how to do it in a loop.
        >
        >
        > Thanks,
        >
        > Greg
        >
        >
        >
        > Gregory L. Hering
        > (256) 722-6420
        > 4807 Bradford Dr
        > Benchmark Electronics, Inc.
        > Huntsville, Al 35805
        >
        >
        >


        __________________________________
        Do you Yahoo!?
        SBC Yahoo! DSL - Now only $29.95 per month!
        http://sbc.yahoo.com
      • greg.hering@bench.com
        You is super-cool and you ain t no fool! Or, to be more precise, your response to my inquiry was insightful and accurate. It seems that the second form
        Message 3 of 3 , Jul 1, 2003
        • 0 Attachment
          You is super-cool and you ain't no fool!

          Or, to be more precise, your response to my inquiry was insightful and accurate.
          It seems that the second form produces the same results, but is more 'anonymous' because you don't have to know the name of the hash key.

          Thanks!

          My Homework Assignment: Delving into the @$ and $$ signs of the world.

          Gregory L. Hering
          (256) 722-6420
          4807 Bradford Dr
          Benchmark Electronics, Inc.
          Huntsville, Al 35805

          -----Original Message-----
          From: Mark Reed [mailto:intensity_guy@...]
          Sent: Monday, June 30, 2003 11:56 PM
          To: perl-beginner@yahoogroups.com
          Subject: Re: [PBML] XML parsing

          If I understand, your only having problems when $type
          is an array correct?

          In the case that $type is an array, The array will
          contain hash references. Each hash will have a key of
          'name', and a 'value' of the directory.

          I think this is the loop your looking for:

          if ($type eq "ARRAY") {
                  foreach my $hash (@$dirs) {
                          print "$$hash{name}\n";
                  }
          }

          Or:
          if ($type eq "ARRAY") {
                  foreach my $hash (@$dirs) {
                          foreach my $value ( values %$hash ) {
                                  print "$value \n";
                          }
                  }
          }

          <SNIPPed>
        Your message has been successfully submitted and would be delivered to recipients shortly.