'Perl: Create a hash file using a loop

I import data from an XML-file and want to output the content into a log-file. Doing this I created for each entity a scalar (2). To output the entities with a loop I created a hash (3 and 4b) and with the for loop I output the name of the tag (entity) and the value (5). To get a specified order I use Tie::IxHash. Now, I wonder if I could avoid steps (3) and (4b) using a for loop. For example I could put the scalars $x1,$x2 and $x3 in an array and doing the steps (3) and (4b) with a loop. Is it possible?

use strict; 
use warnings;
use Data::Dumper;
use Tie::IxHash;

my $x1 = 'a';
my $x2 = '';
my $x3 = undef;  # no xml tag <x3>; 
 
# (3) Create a hash to output values in a log files using for
my $rx1 = \$x1;
my $rx2 = \$x2;
my $rx3 = \$x3;

# (4a) To make an ordered hash use Tie::IxHash
my %h;
tie %h, 'Tie::IxHash'; 
%h = ( 'x1' => $rx1
     , 'x2' => $rx2
     , 'x3' => $rx3);

# (4c) Output hash with undex content gives a warning 
print map { "$_ ${$h{$_}}\n" } keys %h;   # 51
# Use of uninitialized value in concatenation (.) or string at test.pl line 51. 

print "--------\n";
# (5) Output content of hash into a log file
print "using keys from hash:\n";
foreach my $k (keys %h)  {
    if ( not defined ${$h{$k}} or  ${$h{$k}} eq "" ) {${ $h{$k}} = undef; }
    if ( defined ${$h{$k}} ) { print "$k :  ${$h{$k}} \n";   } else {print  "$k :  undef\n"; }    
}

This gives the output:

# Output: 
# Use of uninitialized value in concatenation (.) or string at test.pl line 51.
# x1 a
# x2 
# x3 
# --------
# using keys from hash:
# x1 :  a 
# x2 :  undef
# x3 :  undef 

Update 1:

Thanks to Dave Cross I came up with this. It works for me.

#  Define hash [(step (1)-(4)]
%h = ( 'x1' => my $x1
     , 'x2' => my $x2
     , 'x3' => my $x3
     );

# import from xml
$h{x1} = 'a';
$h{x2} = '';
$h{x3} = undef;

# (5) Output content of hash into a log file
print "using keys from hash:\n";
foreach my $k (keys %h)  {
    if ( not defined $h{$k} or  $h{$k} eq "" )  { $h{$k} = undef; }
    if ( defined $h{$k} ) { print "$k :  $h{$k} \n";   } else {print  "$k :  undef\n"; }    
}

Update 2

I simplified thanks to suggestions of choroba and Dave Cross. Now it is short and organized. I learned that you can assign data from interfaces directly into scalars which are within a hash or an array. Usually I like to declare scalar variables separatly but in this, if you have a myriad of variables it makes sense to write it only once into a hash or array and to declare the hash or array separatly.

#  Define hash [(step (1)-(4)]
%h = ( x1 => $xpc->findvalue('./X1',$node1)
     , x2 => $xpc->findvalue('./X2',$node1)
     , x3 => $xpc->findvalue('./X3',$node1)
     );

# (5) Output content of hash into a log file
print "using keys from hash:\n";
for my $k (keys %h)  {
    if ( not defined $h{$k} or  $h{$k} eq "" )  { $h{$k} = undef; }
    if ( defined $h{$k} ) { print "$k :  $h{$k} \n";   } else {print  "$k :  undef\n"; }    
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source