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.
Test code:
#!/usr/bin/env perl
use strict;
use warnings;
my $default = 'default';
my $default_loc_name = "SCALAR:$default";
my $default_loc_name_ref = \$default_loc_name;
my $getToysResults = {
'Toys' => bless( {
'Toy' => [
bless( {
'ToyLocations' => bless( {
'ToyLocation' => sub { 1 }
}, 'ArrayOfToyLocation' ),
}, 'corrupt' ),
bless( {
'ToyLocations' => bless( {
'ToyLocation' => $default
}, 'ArrayOfToyLocation' ),
}, 'Scalar' ),
bless( {
'ToyLocations' => bless( {
'ToyLocation' => $default_loc_name_ref
}, 'ArrayOfToyLocation' ),
}, 'Scalarref' ),
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 $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;
warn 'Data corrupt' unless defined $location_array_ref;
for my $location_array_hash_ref (@$location_array_ref) {
print $location_array_hash_ref->{locationName}, "\n";
}
}
Output:
$ pm_parse_soap_ref.pl
Data corrupt at ./pm_parse_soap_ref.pl line 69.
default
SCALAR:default
HASH:toybox
ARRAY:toybox
ARRAY:shelf