Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re^4: Parsing SOAP::Lite results

by Roboz (Novice)
on Sep 28, 2012 at 12:52 UTC ( #996206=note: print w/ replies, xml ) Need Help??


in reply to Re^3: Parsing SOAP::Lite results
in thread Parsing SOAP::Lite results

I see what's causing my issue with the 'Not an ARRAY ref' error. When there is only one location it's not an array.

$VAR1 = { 'Toys' => bless( { 'Toy' => [ bless( { 'ToyLocations' => bless( { 'ToyLocation' => { 'toyQuantity' => '2', 'locationName' => 'toy +box' } }, 'ArrayOfToyLocation' ), 'color' => 'brown', 'toyName' => 'bear', 'size' => 'large' }, 'Stuffed' ), bless( { 'ToyLocations' => bless( { 'ToyLocation' => [ { 'toyQuantity' => '1', 'locationName' => 'toy +box' }, { 'toyQuantity' => '4', 'locationName' => 'she +lf' } ] }, 'ArrayOfToyLocation' ), 'color' => 'none', 'toyName' => 'Sorry', 'size' => 'medium' }, 'Board' ) ] }, 'ArrayOfToy' ) };

Still stuck on what to do in this case. Would this be where introspection comes in?  pseudo:(if HASH, then ... %$location) elsif ARRAY, then ... @$location)  ? Thanks to all who are helping me learn this!


Comment on Re^4: Parsing SOAP::Lite results
Select or Download Code
Re^5: Parsing SOAP::Lite results
by Anonymous Monk on Sep 28, 2012 at 12:57 UTC

    Yes, ref is ref

Re^5: Parsing SOAP::Lite results
by kcott (Abbot) on Sep 28, 2012 at 13:21 UTC

    You can use ref to do that.

    Here's a modification of my earlier script to show this. For illustration purposes, I've made minor changes to the locationName values so you can see which toybox is being referred to.

    #!/usr/bin/env perl use strict; use warnings; my $getToysResults = { 'Toys' => bless( { 'Toy' => [ bless( { 'ToyLocations' => bless( { 'ToyLocation' => { 'toyQuantity' => '2', 'locationName' => 'HASH:toybox +' } }, 'ArrayOfToyLocation' ), 'color' => 'brown', 'toyName' => 'bear', 'size' => 'large' }, 'Stuffed' ), bless( { 'ToyLocations' => bless( { 'ToyLocation' => [ { 'toyQuantity' => '1', 'locationName' => 'ARRAY:toybo +x' }, { 'toyQuantity' => '4', 'locationName' => 'ARRAY:shelf +' } ] }, 'ArrayOfToyLocation' ), 'color' => 'none', 'toyName' => 'Sorry', 'size' => 'medium' }, 'Board' ) ] }, 'ArrayOfToy' ) }; foreach my $e (@{$getToysResults->{Toys}{Toy}}) { my $location_ref = $e->{ToyLocations}{ToyLocation}; my $location_array_ref = ref($location_ref) eq 'ARRAY' ? $location_ref : [ $location_ +ref ]; for my $location_array_hash_ref (@$location_array_ref) { print $location_array_hash_ref->{locationName}, "\n"; } }

    Output:

    $ pm_parse_soap_ref.pl HASH:toybox ARRAY:toybox ARRAY:shelf

    -- Ken

      That worked great. I had tried some  if (ref($location_ref) eq 'ARRAY') {...} elsif (ref($location_ref) eq 'HASH') {...} and just changed the @$ to a %$ and was getting a 'Can't use string ... strict refs' error. Glad you returned with the better way to do it.

      Can you tell me what's happening here?

      my $location_array_ref = ref($location_ref) eq 'ARRAY' ? $location_ref : [ $location_ +ref ];

      Thank you very much!

        That's the Conditional Operator. You'll often see it referred to as the ternary operator (actually, that's what I usually call it). That single statement could be written as:

        my $location_array_ref; if (ref($location_ref) eq 'ARRAY') { $location_array_ref = $location_ref; } else { $location_array_ref = [ $location_ref ]; }

        There's an assumption here that if it's not an arrayref, it will be a hashref. That seemed like a reasonable assumption to me; especially for a short script intended to demonstrate a technique. Furthermore, trying to guess what other data types you might be working with would simply be other assumptions.

        The basic syntax for this operator is:

        expression1 ? expression2 : expression3

        There's nothing to say how complex any of those expressions might be; in fact, any of them could include another ternary operator.

        Putting all that together, here's an example of far more robust code that allows arrayrefs, hashrefs, scalarrefs and non-reference scalar values with anything else generating an error.

        foreach my $e (@{$getToysResults->{Toys}{Toy}}) { my $location_ref = $e->{ToyLocations}{ToyLocation}; my $ref_type = ref $location_ref; my $location_array_ref = $ref_type eq 'ARRAY' ? $location_ref : $ref_type eq 'HASH' ? [ $location_ref ] : $ref_type eq 'SCALAR' ? [ { locationName => $$location_ref } + ] : $ref_type eq '' ? [ { locationName => $location_ref } +] : undef; die 'Data corrupt' unless defined $location_array_ref; for my $location_array_hash_ref (@$location_array_ref) { print $location_array_hash_ref->{locationName}, "\n"; } }

        If you want to play around with this, here's the code I used for my tests and the output. Note that I changed die to warn to see all conditions being exercised in a single run.

        -- Ken

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://996206]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (6)
As of 2015-07-06 03:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (69 votes), past polls