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

Hello All,

I am trying to parse a JSON response from a Google API and am having a bit of trouble figuring out what is the right syntax to get the correct field values.  The program flow is to call the API then map the responses into my variables.  So the call looks like this: 
<$geocoder = Geo::Coder::Google->new(apiver => 3); eval { $latlong = $geocoder->geocode(location => $location); print Dumper($latlong); }; $map_coords = $latlong->{geometry}{location}{lat} . " +" . $latlong->{geometry}{location}{lng}; $country = $latlong->{address_components}{types}{count +ry}{long_name};

My problem is in the mapping for $COUNTRY.  In the JSON response, which dumps as follows, I get an error in trying to grab the long_name of the country out of the types (which I thought was a hash, but according to the error, it isn't):
$VAR1 = { 'formatted_address' => 'Johannesburg, South Africa', 'types' => [ 'locality', 'political' ], 'address_components' => [ { 'types' => [ 'locality', 'political' ], 'short_name' => 'Johannesburg', 'long_name' => 'Johannesburg' }, { 'types' => [ 'administrative_are +a_level_3', 'political' ], 'short_name' => 'Johannesburg', 'long_name' => 'Johannesburg' }, { 'types' => [ 'administrative_are +a_level_2', 'political' ], 'short_name' => 'City of Johanne +sburg Metropolitan Municipality', 'long_name' => 'City of Johannes +burg Metropolitan Municipality' }, { 'types' => [ 'administrative_are +a_level_1', 'political' ], 'short_name' => 'GP', 'long_name' => 'Gauteng' }, { 'types' => [ 'country', 'political' ], 'short_name' => 'ZA', 'long_name' => 'South Africa' } ], 'geometry' => { 'viewport' => { 'southwest' => { 'lat' => '- +26.2389231', 'lng' => '2 +7.942449' }, 'northeast' => { 'lat' => '- +26.1041199', 'lng' => '2 +8.1376001' } }, 'location' => { 'lat' => '-26.2041028', 'lng' => '28.0473051' }, 'location_type' => 'APPROXIMATE', 'bounds' => { 'southwest' => { 'lat' => '-26 +.2389231', 'lng' => '27. +942449' }, 'northeast' => { 'lat' => '-26 +.1041199', 'lng' => '28. +1376001' } } } }; Not a HASH reference at cvlt_jobs_2 line 239.
If the correct answer is 'South Africa' (address_components >> types >> country >> long_name), how do I grab that? 

Replies are listed 'Best First'.
Re: Parsing a JSON response
by Your Mother (Archbishop) on Jul 25, 2014 at 18:43 UTC

    To clarify, you are not parsing a JSON response, you are using a Perl data structure returned by the module. There no JSON handling in your code and it’s irrelevant to what you’re doing whether or not Geo::Coder::Google does so under the hood. I also think this is closer to the kind of approach you want than assuming data positions will remain immutable–

    my $location = $geocoder->geocode(location => "STRING"); for my $component ( @{ $location->{address_components} } ) { next unless grep $_ eq "country", @{$component->{types}}; print $component->{long_name}, $/; }
      Yes, thanks for the correction - I'm just parsing the data structure created by the module - I'm not doing it myself. And thanks for the tip on the structures as the positions are indeed not immutable. I will study this. Thanks for the help!
Re: Parsing a JSON response
by wjw (Priest) on Jul 25, 2014 at 18:19 UTC

    $VAR1->{'address_components'}->[4]->{'long_name'}

    works for me...

    Hope that helps....

    Update:I think that you are seeing {'address_components'} as part of the 'types' data sub-structure. It is not. "types' is a hash key at the same structural level as the hash key 'address_components'. In other words, both are keys in the same hash. 'types' references an array containing locality and political. 'address_component' references an array of hashes, one of which seems to be a duplicate of the array pointed at by the aforementioned 'types' key...

    ...the majority is always wrong, and always the last to know about it...

    Insanity: Doing the same thing over and over again and expecting different results...

    A solution is nothing more than a clearly stated problem...otherwise, the problem is not a problem, it is a facct

      Note that that can be written:

      $VAR1->{address_components}[4]{long_name}

      which is more consistent with the OP's usage and reads better (at least to my eye) because it reduces clutter.

      Perl is the programming world's equivalent of English
      Ah, enlightenment. I kept trying things like {type[4]}but that wasn't getting me anywhere. Thank you!
      I don't yet follow you but I am hanging on with everything I have.

      If both "address_components' AND 'types' are keys within the same hash, then what is the value pair for 'address_components'? I'm having trouble wrapping my head around that... Indeed, I thought types was a substructure within 'address_components'...

        Does this rehohy output help?

        my $VAR1; $VAR1->{formatted_address} = "Johannesburg, South Africa"; #d0 $VAR1->{types}[0] = "locality"; #d1 $VAR1->{types}[1] = "political"; #d1 $VAR1->{address_components}[0]{types}[0] = "locality"; #d3 $VAR1->{address_components}[0]{types}[1] = "political"; #d3 $VAR1->{address_components}[0]{short_name} = "Johannesburg"; #d2 $VAR1->{address_components}[0]{long_name} = "Johannesburg"; #d2 $VAR1->{address_components}[1]{types}[0] = "administrative_area_level_3"; #d3 $VAR1->{address_components}[1]{types}[1] = "political"; #d3 $VAR1->{address_components}[1]{short_name} = "Johannesburg"; #d2 $VAR1->{address_components}[1]{long_name} = "Johannesburg"; #d2 $VAR1->{address_components}[2]{types}[0] = "administrative_area_level_2"; #d3 $VAR1->{address_components}[2]{types}[1] = "political"; #d3 $VAR1->{address_components}[2]{short_name} = "City of Johannesburg Metropolitan Municipality"; #d2 $VAR1->{address_components}[2]{long_name} = "City of Johannesburg Metropolitan Municipality"; #d2 $VAR1->{address_components}[3]{types}[0] = "administrative_area_level_1"; #d3 $VAR1->{address_components}[3]{types}[1] = "political"; #d3 $VAR1->{address_components}[3]{short_name} = "GP"; #d2 $VAR1->{address_components}[3]{long_name} = "Gauteng"; #d2 $VAR1->{address_components}[4]{types}[0] = "country"; #d3 $VAR1->{address_components}[4]{types}[1] = "political"; #d3 $VAR1->{address_components}[4]{short_name} = "ZA"; #d2 $VAR1->{address_components}[4]{long_name} = "South Africa"; #d2 $VAR1->{geometry}{viewport}{southwest}{lat} = -26.2389231; #d3 $VAR1->{geometry}{viewport}{southwest}{lng} = 27.942449; #d3 $VAR1->{geometry}{viewport}{northeast}{lat} = -26.1041199; #d3 $VAR1->{geometry}{viewport}{northeast}{lng} = 28.1376001; #d3 $VAR1->{geometry}{location}{lat} = -26.2041028; #d2 $VAR1->{geometry}{location}{lng} = 28.0473051; #d2 $VAR1->{geometry}{location_type} = "APPROXIMATE"; #d1 $VAR1->{geometry}{bounds}{southwest}{lat} = -26.2389231; #d3 $VAR1->{geometry}{bounds}{southwest}{lng} = 27.942449; #d3 $VAR1->{geometry}{bounds}{northeast}{lat} = -26.1041199; #d3 $VAR1->{geometry}{bounds}{northeast}{lng} = 28.1376001; #d3

        See also references quick reference

        see also

        chromatics free book Modern Perl a loose description of how experienced and effective Perl 5 programmers work....You can learn this too.
        Learn Perl in about 2 hours 30 minutes