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

Hello all!

I'm pretty new to perl, and am currently trying to throw together a script that will parse some XML for me. Here's a sample of what's giving me trouble:
use strict; use LWP; use XML::Simple; use Data::Dumper; my $var_lat = "45.96968"; my $var_lon = "-93.33434899999997"; my $ua = LWP::UserAgent->new; my $forecast_xml = $ua->request(HTTP::Request->new(GET => "http://fore +cast.weather.gov/MapClick.php?lat=$var_lat&lon=$var_lon&unit=0&lg=eng +lish&FcstType=dwml")); my $forecast_arr = XMLin($forecast_xml->content); foreach my $item (@{$forecast_arr->{'data'}->[0]->{'time-layout'}}) { print Dumper $item; }
If run, you'll see what I'm dealing with - a hash which contains hashes, all of which have the same name (VAR1) but contain different data.

My goal is to extract each period-name to a separate variable (ie. $name0="Today", $name1="Tonight", $name2="Tuesday", etc). I'm only interested in the period names associated with layout-key 'k-p12h-n13-1', however; the rest are inconsequential.

Trouble is, I'm not sure how best to do that. I tried simply picking out the correct hash numerically, but the incoming XML frequently changes the order. The data in the first hash now might be in the third hash later today.

How can I "single out" just the hash associated with layout-key 'k-p12h-n13-1', and get the needed data out?

Replies are listed 'Best First'.
Re: Nested hashes, non-unique names
by choroba (Cardinal) on Mar 17, 2014 at 15:08 UTC
    You can use grep to pick a member from an array. You can use map to turn the list of hash refs to a list of values stored inside of them.
    #!/usr/bin/perl use strict; use LWP; use XML::Simple; use Data::Dumper; my $var_lat = "45.96968"; my $var_lon = "-93.33434899999997"; my $ua = LWP::UserAgent->new; my $forecast_xml = $ua->request(HTTP::Request->new(GET => "http://fore +cast.weather.gov/MapClick.php?lat=$var_lat&lon=$var_lon&unit=0&lg=eng +lish&FcstType=dwml")); my $forecast_arr = XMLin($forecast_xml->content); my ($item) = grep 'k-p12h-n13-1' eq $_->{'layout-key'}, @{ $forecast_arr->{data}[0]{'time-layout'} }; my @names = map $_->{'period-name'}, @{ $item->{'start-valid-time'} }; print "@names\n";

    Update: The structure you are dealing with is not a hash of hashes, but an array of hashes (that's why you were able to iterate for over it). VAR1 is not a key, it is just what Data::Dumper adds to the output.

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      Perfect! Thanks for the help.
      One other stupid question...

      I realized within the past day that the layout key sometimes changes. It was "k-p12h-n13-1" when I first posted, but since then they changed it to "k-p12h-n14-1".

      Having looked at some old data, it seems as though the one part which never changes is "k-p12h-n".

      I've been trying to modify the grep above to match that, but am having no success. Have tried umpteen different ways so far, but none have worked. (I can change the operator from "eq" to "=~" without breaking it, which seems to be a step in the right direction. But if the pattern isn't contained within single quotes it breaks, and I can't seem to use a regex within single quotes, nor get it to match a partial string within single quotes.)

      grep /k-p12h-n/ =~ $_->{'layout-key'}

      was the first thing that came to my mind, but that's clearly not correct. I know I'm missing something here, I'm just not seeing what...

        The string to match goes on the left, the pattern on the right:
        grep $_->{'layout-key'} =~ /k-p12h-n/,
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Nested hashes, non-unique names
by Jenda (Abbot) on Mar 18, 2014 at 09:55 UTC