I am trying to check if a BIG hash has any keys from small hash and see if they exist, and if they do modify the BigHash with updated values from small hash.
So the lookup hash would look like this :
configure =(
CommonParameter => {
'SibSendOverride' => 'true',
'SibOverrideEnabledFlag' => 'true',
'SiPosition' => '8',
'Period' => '11'
}
)
But the BigHash is very very nested.. The key/hash CommonParameter from the small hash configure is there in the BigHash.
Can somebody help/suggest some ideas for me please?
Here is an example BigHash :
%BigHash = (
'SibConfig' => {
'CELL' => {
'Sib9' => {
'HnbName' => 'HnbName',
'CommonParameter' => {
'SibSendOverride' => 'false',
'SibMaskOverrideEnabledFlag' => 'false',
'SiPosition' => '0',
'Period' => '8'
}
}
}
},
)
I hope I was clear in my question. Trying to modify values of heavily nested BigHash based on Lookup Hash if those keys exist.
Can somebody help me? I am not approaching this in the right way. Is there a neat little key lookup fucntion or something available perhaps?
Give Data::Search a try.
use Data::Search;
#results = Data::Search::datasearch(
data => $BigHash, search => 'keys',
find => 'CommonParameter',
return => 'hashcontainer');
foreach $result (#results) {
# result is a hashref that has 'CommonParameter' as a key
if ($result->{CommonParameter}{AnotherKey} ne $AnotherValue) {
print STDERR "AnotherKey was ", $result->{CommonParameter}{AnotherKey},
" ... fixing\n";
$result->{CommonParameter}{AnotherKey} = $AnotherValue;
}
}
Is there a way to update a value in a hash using a hash reference that points to the hash value?
My hash output looks like this:
'Alternate' => {
'free' => '27.52',
'primary' => 'false',
'used' => '0.01',
'name' => '/mydir/journal2',
'size' => '50.00'
},
'Primary' => {
'free' => '60.57',
'primary' => 'true',
'used' => '0.06',
'name' => '/mydir/journal',
'size' => '64.00'
}
};
I attempted to create a hash reference to the 'used' property in the hash and tried to update the value:
$hash_ref = \%hash->{"Primary"}->{used};
$hash_ref = "99%";
print $$hash_ref, "\n";
This changes the value of the hash, but I get the "Using a hash as a reference is deprecated at line X". I'd like to know if what I'm trying to do is possible and what I'm doing wrong.
...
'Primary' => {
'free' => '60.57',
'primary' => 'true',
'used' => '0.06',
'name' => '/mydir/journal',
'size' => '64.00'
}
...
Try to bypass the deprecation problem doing it like this:
...
my $hash_ref = $hash{'Primary'}; # if you declared `%hash = ( .. );`
# Or my $hash_ref = $hash->{'Primary'}; if you declared `$hash = { .. };`
print $hash_ref->{used}; # Prints 0.06
$hash_ref->{used} = '0.07'; # Update
print $href->{used}; # Prints 0.07
...
See perldsc, if you want to learn more.
Your failure started because you tried to create a hash reference to a scalar. That's kind of a meaningless goal as those are different data types. As Filippo already demonstrated, you already have hash references as values of your greater hash, so you can rely on that.
However, if you really want to create a reference to the scalar, you can just edit that value. This is how you'd do it:
use strict;
use warnings;
my $h = {
'Alternate' => {
'free' => '27.52',
'primary' => 'false',
'used' => '0.01',
'name' => '/mydir/journal2',
'size' => '50.00',
},
'Primary' => {
'free' => '60.57',
'primary' => 'true',
'used' => '0.06',
'name' => '/mydir/journal',
'size' => '64.00',
}
};
my $primary = $h->{Primary};
print $primary->{used}, "\n"; # Outputs 0.06
my $usedref = \$h->{Primary}{used};
$$usedref = '0.07';
print $primary->{used}, "\n"; # Outputs 0.07
I'm struggling with a bug, that I can't nail down.
I have a function that takes a postcode, does a lookup, and returns a latitude, longitude and area name.
for example, pass it AD300 it returns (something like) 42.6, 1.55, ordino - it works very well.
The function is called like this:
my ($lat, $lng, $area) = $object->release();
The return values are fine, and I can print them in perl with a warn
warn "Area $area, $rellat, $rellng";
This works fine. "Area Ordino, 42.6, 1.55"
I then take one of these values, say $area, add it to a hash of data, and pass it to a web page where it is preprocessed via TT (as I do successfully with a load of other variables).
I'm assigning the value to the hash in the normal way. e.g.
$hash->{'area'} = $area;
Here is where the fun begins. When I try to reference the value in TT e.g. [% hash.area %]
I don't get "Ordino" printed on the web page, I'm told I've passed an Array reference to TT.
After a little debugging, I've found that my hash variable hash.area, is somehow referencing an array (according to TT) holding the three values that I've returned from the subroutine "release". I.e.
hash.area = [42.6, 1.55, ordino] according to TT.
That is, to get the value "Ordino" within the web page, I have to access [% hash.area.2 %].
Further, I can set $hash->{'area'} to equal any of the variables, $lat, $lng, or $area and get the same behavior. TT believes all three variables reference the same array. that is
$lat = $lng = $area = [42.6, 1.55, ordino] according to TT
This is bizare, I can happily print the variables in perl and they appears as normal - not an array. I've tried dumping the hash with dumper, no array, everything is fine. Yet somehow, TT is finding an array. It's doing my head in.
The site is quite large, with a lot of pages and I happily pass variables and hashes via TT to web pages all the time, and have been for 4 years now. I've never seen this. On other pages, I even pass exactly the same output from the "release" method and it is processed correctly.
I don't think my TT processing code is the problem, however the following is relevant.
my $tt = Template->new({
INCLUDE_PATH => [ #$template_directories ],
COMPILE_EXT => '.ttc',
COMPILE_DIR => '/tmp/ttc',
FILTERS => YMGN::View->filters,
PLUGIN_BASE => [ 'YMGN::V::TT::Plugins' ],
EVAL_PERL => 1
});
$self->{tt} = $tt;
$self->{template_directories} = $template_directories;
$self->{output} = $params->{output} || undef;
$self->{data} = $params->{data} || [];
The above creates a new tt object and is part of the "new" function (refed below).
"data" contains the hash. "output" holds the processed template ready to send to users browser. We call new (above), process the data and create the output with the code below.
sub process {
my $self = shift;
my $params = shift;
if (!ref $self || !exists $self->{tt}) {
my $class = $self;
$self = $class->new($params);
}
if (!$self->{output}) {
die "You need to specify output";
}
delete $self->{error};
$self->y->utils->untaint(\$self->{template});
my $rv = $self->{tt}->process(
$self->{template},
$self->{data},
$self->{output},
binmode => ':utf8',
);
if (!$rv) {
warn $self->{tt}->error();
return {
error => $self->{tt}->error(),
};
}
return 0;
}
All of the above is sanitised because there is a lot of other stuff going on.
I believe what's important is that the data going in looks correct, here is a full dump of the complete data that is being processed by tt (at the point of processing). The thing that is causing the problem is bubbles->[*]->{'release'} (note, that release == area in the data. The name was changed for unrelated reasons). As you can see, dumper thinks it's a string. TT deals with everything else fine.
data $VAR1 = {
'system' => {
system stuff
},
'features' => {
site feature config
},
'message_count' => '0',
'bubbles' => [
bless( {
'history' => [
{
'creator' => '73',
'points' => '10',
'screenname' => 'sarah10',
'classname' => 'Flootit::M::Bubbles',
'id' => '1378',
'updated' => '1352050471',
'type' => 'teleport',
'label' => 'teleport',
'class' => 'Flootit::M::Bubbles'
}
],
'creator' => '6',
'release' => 'Escaldes-Engordany',
'image' => 'http://six.flooting.com/files/833/7888.png',
'pop_time' => '1352050644',
'y' => $VAR1->{'y'},
'taken_by' => '0',
'city' => '3',
'title' => 'hey a new bubble',
'id' => '566',
'class' => 'Flootit::M::Bubbles',
'prize' => 'go for it kids'
}, 'Flootit::M::Bubbles' ),
bless( {
'history' => [
{
'creator' => '6',
'points' => '10',
'screenname' => 'sarah20',
'classname' => 'Flootit::M::Bubbles',
'id' => '1723',
'updated' => '1349548017',
'type' => 'teleport',
'label' => 'teleport',
'class' => 'Flootit::M::Bubbles'
},
{
'creator' => '6',
'points' => '5',
'screenname' => 'sarah20',
'classname' => 'Flootit::M::Bubbles',
'id' => '1732',
'updated' => '1349547952',
'type' => 'blow',
'label' => 'blow',
'class' => 'Flootit::M::Bubbles'
}
],
'creator' => '89',
'release' => 'Ordino',
'image' => 'http://six.flooting.com/files/1651/8035.png',
'pop_time' => '1351203843',
'y' => $VAR1->{'y'},
'taken_by' => '0',
'city' => '3',
'title' => 'test4',
'id' => '1780',
'class' => 'Flootit::M::Bubbles',
'prize' => 'asdfasdf dsadsasdfasdfasdf'
}, 'Flootit::M::Bubbles' ),
bless( {
'history' => [],
'creator' => '6',
'release' => 'Andorra la Vella',
'image' => 'http://six.flooting.com/files/1671/8042.png',
'pop_time' => '0',
'y' => $VAR1->{'y'},
'taken_by' => '0',
'city' => '3',
'title' => 'Pretty flowers, tres joli',
'id' => '1797',
'class' => 'Flootit::M::Bubbles',
'prize' => 'With lots of pretty pictures'
}, 'Flootit::M::Bubbles' ),
bless( {
'history' => [],
'creator' => '6',
'release' => 'Hillrise Ward',
'image' => 'http://six.flooting.com/files/1509/8003.png',
'pop_time' => '0',
'y' => $VAR1->{'y'},
'taken_by' => '0',
'city' => '3',
'title' => 'Test beats',
'id' => '1546',
'class' => 'Flootit::M::Bubbles',
'prize' => 'Sound great'
}, 'Flootit::M::Bubbles' )
]
};
What comes out after processing is this (in $output)
There is a
[% FOREACH floot IN bubbles %]
Floating around ARRAY(0xfaf5d448). from [% floot.release %]
if we make this [% floot.release.2 %] it gives the correct value.
All the other fields can be referenced correctly - go figure.
The code that puts "bubbles" together is;
my $bubbles = $y->model('Bubbles')->search(['type' => 'golden', 'image' => '!NULL',
'bubble_prizes' => ['p', { 'p.bubble' => 'self.id'}], ], {
order_by => '(created>CURRENT_DATE() AND thumbsup+thumbsdown<10) DESC, COALESCE(thumbsup,0)-COALESCE(thumbsdown,0) DESC, pop_time DESC',
count => 10,
fields => ['p.title as title', 'p.prize as prize', 'city', 'taken_by', 'pop_time', 'id', 'creator'],
});
for (my $i=0; $i<#$bubbles; $i++) {
# Find specified bubbles (see below for when not found here)
my ($rellat, $rellng, $area) = $bubbles->[$i]->release() ;
$bubbles->[$i]->{'release'} = $area;
}
}
The controller then takes $bubble, bundles it up with session / site data, puts it inside an anonymous hash (as you can see in the data above) and passes it to view for processing.
The code for release is :
sub release {
my $self = shift;
my $postcode = $self->y->model('Prizes')->find({bubble => $self->id})->postcode;
my ( $user_lat, $user_long, $region_name );
if($postcode)
{
( $user_lat, $user_long, $region_name ) = $self->y->api('Location')->from_postcode($postcode);
return ( $user_lat, $user_long, $region_name );
}
}
API::Location is quite large, however the relevant lines are;
$postcode_record = $self->y->model('GeoData')->find( {
source => "ALL_COUNTRIES_POSTCODES",
country => $country_code,
sourceid => $postcode, } );
return ( $postcode_record->latitude, $postcode_record->longitude, $postcode_record->town );
The data dumps I've shown you are taken from inside TT.pm (part of view).
So, any ideas what might be going on or where to start? What can I do to try and debug this further? I'm out of ideas.
Maybe it's because $area is a blessed object; Try this to convert to a scalar string :
$string = ''.$area;
# e.g.
$hash->{'area'} = ''.$area;
Following #Moritz comment, to check that $area is blessed:
print ref($area);
use Data::Dumper; warn Dumper($area);
And q{""} overloaded:
print defined ${ref($area).'::'}{'(""'};
EDIT
sub release can return
- undef if $postcode evaluate to false
- a list but as it is used in as scalar context returns the last argument $region_name like parenthesized list (comma expression)
sub release {
my $self = shift;
my $postcode = $self->y->model('Prizes')->find({bubble => $self->id})->postcode;
my ( $user_lat, $user_long, $region_name );
if($postcode)
{
( $user_lat, $user_long, $region_name ) = $self->y->api('Location')->from_postcode($postcode);
return ( $user_lat, $user_long, $region_name );
}
}
It will be relevant to Dump $region_name or $area, or to look at from_postcode.
I found that the problem went away on other development servers and the production server.
I therefore tried uninstalling and reinstalling TT, however that didn't help.
As it appears it's an environment issue on my dev server, so I am retiring the box and starting a new one.
Problem:
Seeing exists argument is not a HASH or ARRAY element
Need help setting up several conditions to grab the right key.
Code: (I'm not sure also if my conditions are set up correctly. Need advice troubleshooting)
my $xml = qx(#cmdargs);
my $data = XMLin($xml);
my $size=0;
# checking for error string, if file not found then just exit
# otherwise check the hash keys for filename and get its file size
if (exists $data->{class} =~ /FileNotFound/) {
print "The directory: $Path does not exist\n";
exit;
} elsif (exists $data->{file}->{path}
and $data->{file}->{path} =~/test-out-XXXXX/) {
$size=$data->{file}->{size};
print "FILE SIZE:$size\n";
} else {
# print "Nothing to print.\n";
}
# print "$data";
print Dumper( $data );
My Data:
Data structure for xml file with FileNotFound:
$VAR1 = {
'file' => {},
'path' => '/source/feeds/customer/testA',
'class' => 'java.io.FileNotFoundException',
'message' => '/source/feeds/customer/testA: No such file or directory.'
};
Data structure for xml file found:
$VAR1 = {
'recursive' => 'no',
'version' => '0.20.202.1.1101050227',
'time' => '2011-09-30T02:49:39+0000',
'filter' => '.*',
'file' => {
'owner' => 'test_act',
'replication' => '3',
'blocksize' => '134217728',
'permission' => '-rw-------',
'path' => '/source/feeds/customer/test/test-out-00000',
'modified' => '2011-09-30T02:48:41+0000',
'size' => '135860644',
'group' => '',
'accesstime' => '2011-09-30T02:48:41+0000'
},
The interpreter is probably thinking you meant:
exists($data->{class}=~/FileNotFound/)
Try:
exists $data->{class} and $data->{class}=~/FileNotFound/
instead.
I posted "How to undersand the POE-Tk use of destroy?" in an attempt to reduce the bug in my production code to a test case. But it seems that the solution to the test case is not working in the full program.
The program is 800+ lines long so I am hesitant to post it in full. I realize that the snippets I provide here may be too short to be of any use, but I hope to get some direction in either where to look for a solution or what additional information I can provide.
Here is the Session::Create section of my POE-Tk app.
POE::Session->create(
inline_states => {
_start => \&ui_start,
get_zone => \&get_zone,
ping => \&ping,
mk_disable => \&mk_disable,
mk_active => \&mk_active,
pop_up_add => \&pop_up_add,
add_button_press => sub {
my ($kernel, $session, $heap) = #_[KERNEL, SESSION, HEAP];
print "\nadd button pressed\n\n";
&validate;
},
ih_button_1_press => sub {
my ($kernel, $session, $heap) = #_[KERNEL, SESSION, HEAP];
print "\nih_button_1 pressed\n\n";
if( Tk::Exists($heap->{ih_mw}) ) {
print "\n\nih_mw exists in ih_button_1_press\n\n";
} else {
print "\n\nih_mw does not exist in ih_button_1_press\n\n";
}
1;
$heap->{ih_mw}->destroy if Tk::Exists($heap->{ih_mw});
&auth;
},
pop_up_del => \&pop_up_del,
auth => \&auth,
# validate => \&validate,
auth_routine => \&auth_routine,
raise_widget => \&raise_widget,
del_action => \&del_action,
over => sub { exit; }
}
);
add_button_press is called here;
sub pop_up_add {
...
my $add_but_2 = $add_frm_2->Button(
-text => "Add Record",
-command => $session->postback("add_button_press"),
-font => "{Arial} 12 {bold}") -> pack(
-anchor => 'c',
-pady => 6,
);
...
}
validate creates the Toplevel widget $heap->{ih_mw};
sub validate {
...
if( ! $valid ) {
print "\n! valid entered\n\n";
$heap->{label_text} .= "Add record anyway?";
my $lt_ref = \$heap->{label_text};
...
my $heap->{ih_mw} = $heap->{add_mw}->Toplevel( -title => "ih_mw");
...
if( Tk::Exists($heap->{ih_mw}) ) {
print "\n\nih_mw exists in validate\n\n";
} else {
print "\n\nih_mw does not exist in validate\n\n";
}
...
my $ih_but1 = $heap->{ih_mw}->Button( -text => "Add",
-font => 'vfont',
-command => $session->postback("ih_button_1_press"),
)->pack( -pady => 5 );
...
}
Pressing $ih_but1 results in this;
C:\scripts\alias\resource>alias_poe_V-3_0_par.pl
add button pressed
sub validate called
! valid entered
ih_mw exists in validate
ih_button_1 pressed
ih_mw does not exist in ih_button_1_press
So the $heap->{ih_mw} widget seems to be unkown to the ih_button_1_press anonymous subroutine even with the inclusion of "($kernel, $session, $heap) = #_[KERNEL, SESSION, HEAP];"
Where does $heap in &validate come from? You don't pass it as a parameter. Could $heap in &validate and $heap in &in_button_1_press not be the same thing? Have you tried printing the stringy form of $heap to see if the addresses are the same in the two functions?