Perl - How to add rows in a hash inside a loop? - perl

Iam trying to create a simple array KEY => VALUE from a json response, here's my results when I dump the array but the keys are not what Im excpecting:
$VAR1 = 'expectedvalue1';
$VAR2 = 'expectedvalue2';
$VAR3 = 'expectedvalue3';
and here's my code that I found some part of it here (some comments says that there's backslash missing)
my %result = ();
foreach my $row (#json_response){
$result{ $row->{"json_key"} } = $row->{"json_value"};
}
print Dumper(%result);
While I'm trying to get
expectedkey1 = expectedvalue1
expectedkey2 = expectedvalue2
expectedkey3 = expectedvalue3
Edit : I made a mistake in the names of keys.

Are you trying to get key => value and key/value have the same values?
If you're looking for that, maybe this can help you
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my #array_items = qw(expectedvalue1 expectedvalue2 expectedvalue3);
my %hash_example;
foreach my $value (#array_items) {
push(#{$hash_example{$value}}, $value);
}
print Dumper(\%hash_example);
OUTPUT:
$VAR1 = {
'expectedvalue2' => [
'expectedvalue2'
],
'expectedvalue1' => [
'expectedvalue1'
],
'expectedvalue3' => [
'expectedvalue3'
]
};

Related

Perl print specific value from decoded json

I'm trying to decode a json then only print specific values from it. I want to get the front and back from the json and save the file. Code is not getting past the decode_base64 and says "Not a HASH reference"
use strict;
use warnings;
use JSON;
use Data::Dumper
use MIME:Base64
my $imageDir = "/usr/documents/images/";
my $testJson = '[{ "front":"", "back":"", "shortID":"", "longID":"" } ]';
my $Json = decode_json($testJson);
print Dumper $Json;
my $fImage = decode_base64($Json->{front});
my $fImagefile = saveFile('Front.jpg',$fImage);
my $bImage = decode_base64($Json->{back});
my $bImagefile = saveFile('Back.jpg',$bImage);
return ($fImagefile, $bImagefile);
sub saveFile{
my ($file $image) = #_;
my imageFile = $imageDir.$file;
open (IMGFILE, '>'.$imageFile) or die;
print IMGFILE $image;
close IMGFILE;
return $imageFile;
}
#ikegami already said this in a comment but I'll expand on it.
You have a JSON fragment that's an array, and the element in the array is a hash. T. You have one more level to drill down into to get what you want. The perldsc (Perl Data Structures Cookbook) has lots of hints and tricks for multi-level data structures:
my $testJson = '[{ "front":"", "back":"", "shortID":"", "longID":"" } ]';
my $Json = decode_json($testJson);
print Dumper $Json;
In your Dumper output you should see something like this. It's an anonymous array with a hashref as its first and only element:
$VAR1 = [
{
'longID' => '',
'shortID' => '',
'front' => '',
'back' => ''
}
];
If you want to process only that element, you can get the first element of the array reference. This is going to be the hash reference that you want to process:
my $element = $Json->[0];
my $fImage = decode_base64($element->{front});
...
But, you might want to process all the elements. Simply wrap a foreach around it:
foreach my $element ( #$Json ) {
my $fImage = decode_base64($element->{front});
...
}
Even though that array dereference is simple, the postfix dereferencing introduced in v5.26 is quite nice and what I use most often:
foreach my $element ( $Json->#* ) {
my $fImage = decode_base64($element->{front});
...
}

how to parse the output of SOAP response which is in HASH format of data? see below code for details

#perl!
use warnings;
use strict;
use XML::Compile::SOAP;
use XML::Compile::SOAP11;
use XML::Compile::WSDL11;
use XML::Compile::Transport::SOAPHTTP;
use Data::Dumper;
##my other variables pointing to wsdl and xsd files.
my $url="http://myhost.com:9080/imws/services/ImpactManager/";
my %inargs_connect = (
"userName" => "xxxx",
"password" => "xxxxxxxxxx",
"imname" => "yyyyyyyyyyy",
"bufferType" => "abcd"
);
my $wsdl = XML::Compile::WSDL11->new;
$wsdl->addWSDL($wsdl_file);
$wsdl->compileCalls(address =>$url);
my ($answer, $trace) = $wsdl->call( 'Connect', %inargs_connect);
print ($answer);
the above code is printing :
HASH(0x47f8b28)
in the last print statement if i use dumper, i get the below response.
print Dumper($answer);
$VAR1 = {
'outargs' => {
'connectionId' => '1557666855346'
}
};
how to parse the required values like,
i need to be able to easily access 'connectionId' and '1557666855346' ?
Any ideas are welcome. Thanks in advance.
Thanks,
Kaushik KM.
$answer appears to be a hash reference, so you'd access the data using normal dereferencing techniques:
my $conn_id = $answer->{outargs}{connectionId};
print "$conn_id\n";
Output:
1557666855346
my %fhash = %{$answer};
my $key = "";
foreach $key (keys %fhash)
{
print "keys are\n \"$key\" its value is (${$answer}{$key}) \n";
foreach my $key2 (keys %${$answer}{$key})
{
print "keys of(${$answer}{$key})\n \"$key2\"\n";
}
}
is not working and is throwing error as follows:
Experimental keys on scalar is now forbidden at CreateEvent.pl line 64.
Type of arg 1 to keys must be hash or array (not key/value hash slice) at Create
Event.pl line 64, near "}
can someone correct this please.
loop through all the keys in answear = { outargs => { key1, key2 }}
# This should remove the error of "Experimental keys on scalar is now forbidden" by wrapping the hashRef in %{}
for ( keys %{$answear->{outargs}}) {
# $_ here will be the key and if you want to access the value use $answear->{outargs}->{$_}
print "key: $_, value: $answear->{outargs}->{$_}\n";
}
output:
key: connectionId, value: 1557666855346
I hope this will help you!

Accessing and modifying a nested hash based on a dot separated string

I have a string as input, say apple.mango.orange = 100
I also have a hash reference:
$inst = {
'banana' => 2,
'guava' => 3,
'apple' => {
'mango' => {
'orange' => 80
}
}
};
I want to modify the value of orange using the input string. Can someone please help me how I could do this?
I tried splitting the string into (key, value) pair. I then did the following on the key string:
my $key2 = "\$inst->{".$key."}";
$key2 =~ s/\./}->{/g;
$$key2 = $value;
This does not work as intended. Can someone help me out here? I have read the Perl FAQ about not using a variable value as variable but I am unable to think of an alternative.
You are building string that consists of (buggy) Perl code, but you never ask Perl to execute it. ...but that's not the right approach.
sub dive_val :lvalue {
my $p = \shift;
$p = \($$p->{$_}) for #_;
$$p
}
my #key = split /\./, "apple.mango.orange";
dive_val($inst, #key) = $value;
or
use Data::Diver qw( DiveVal );
my #key = split /\./, "apple.mango.orange";
DiveVal($inst, map \$_, #key) = $value;
Not only is a symbolic reference a very bad idea here, it doesn't even solve your problem. You're building an expression in $key2, and just jamming another dollar sign in front of its name won't make perl execute that code. For that you would need eval, which is another bad idea
You can install and use the Data::Diver module, which does exactly this sort of thing, or you can simply loop over the list of hash keys, picking up a new hash reference each time and assigning the value to the element with the last key
The biggest issue is actually parsing the incoming string into a list of keys and a value. This code implements a subroutine apply which applies the implied operation in the string to a nested hash. Unless you are confident of your data, it needs some error checking addingto make sure each of the keys in the list exists. The Data:;Dumper output is just to demonstrate the validity of the result
use strict;
use warnings 'all';
use Data::Dumper;
my $inst = { 'banana' => 2, 'guava' => 3, 'apple' => { 'mango' => { 'orange' => 80 } } };
my $s = 'apple.mango.orange = 100';
apply($s, $inst);
print Dumper $inst;
sub apply {
my ($operation, $data) = #_;
my ($keys, $val) = $operation =~ /([\w.]+)\s*=\s*(\d+)/;
my #keys = split /\./, $keys;
my $last = pop #keys;
my $hash = $data;
$hash = $hash->{$_} for #keys;
$hash->{$last} = $val;
}
output
$VAR1 = {
'banana' => 2,
'apple' => {
'mango' => {
'orange' => '100'
}
},
'guava' => 3
};

Hash doesn't print in Perl

I have a hash:
while( my( $key, $value ) = each %sorted_features ){
print "$key: $value\n";
}
but I cannot obtain the correct value for $value. It gives me:
intron: ARRAY(0x3430440)
source: ARRAY(0x34303b0)
exon: ARRAY(0x34303f8)
sig_peptide: ARRAY(0x33f0a48)
mat_peptide: ARRAY(0x3430008)
Why is it?
Your values are array references. You need to do something like
while( my( $key, $value ) = each %sorted_features ) {
print "$key: #$value\n";
}
In other words, dereference the reference. If you are unsure what your data looks like, a good idea is to use the Data::Dumper module:
use Data::Dumper;
print Dumper \%sorted_features;
You will see something like:
$VAR1 = {
'intron' => [
1,
2,
3
]
};
Where { denotes the start of a hash reference, and [ an array reference.
You can use also Data::Dumper::Pertidy which runs the output of Data::Dump through Perltidy.
#!/usr/bin/perl -w
use strict;
use Data::Dumper::Perltidy;
my $data = [{title=>'This is a test header'},{data_range=>
[0,0,3, 9]},{format => 'bold' }];
print Dumper $data;
Prints:
$VAR1 = [
{ 'title' => 'This is a test header' },
{ 'data_range' => [ 0, 0, 3, 9 ] },
{ 'format' => 'bold' }
];
Your hash values are array references. You need to write additional code to display the contents of these arrays, but if you are just debugging then it is probably simpler to use Data::Dumper like this
use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper \%sorted_features;
And, by the way, the name %sorted_features of your hash worries me. hashes are inherently unsorted, and the order that each retrieves the elements is essentially random.

How to loop json results in Perl

I am trying to output JSON from a perl script that accesses a mysql database.
How I can I loop through my query returns and turn that into JSON using the JSON module?
When I do this all I get is 1 return
while($query_handle->fetch()) {
$jsonStructure->{event};
$jsonStructure->{event}->{evid} = $evid;
$jsonStructure->{event}->{component} = $component;
$jsonStructure->{event}->{firstTime} = $firstTime;
$jsonStructure->{event}->{lastTime} = $lastTime;
$jsonStructure->{event}->{count} = $count;
$jsonStructure->{event}->{summary} = $summary;
$jsonStructure->{event}->{severity} = $severity;
}
Basically I have many events and don't know how to say event[0]...
Thank You
I think what you're looking for is this:
push #{ $jsonStructure->{events} }, {
evid => $evid,
component => $component,
...,
};
although even that is probably overkill, because you can probably do something like:
while (my $row = $dbh->fetchrow_hashref) {
push #{ $jsonStructure->{events} }, $row;
}
if all of the column names in the DB are the same as the field names you want in the JSON, and you want all columns, or:
my #keys = qw(evid component firstTime ...);
while (my $row = $dbh->fetchrow_hashref) {
my %hash;
#hash{#keys} = #$row{#keys};
push #{ $jsonStructure->{events} }, \%hash;
}
if you only want some columns, or:
# DB colname => JSON field name
my %mapping = (
event_id => 'evid',
component => 'component',
first_time => 'firstTime',
...,
);
while (my $row = $dbh->fetchrow_hashref) {
my %hash;
#hash{ values %mapping } = #$row{ keys %mapping };
push #{ $jsonStructure->{events} }, \%hash;
}
for a completely arbitrary mapping. Power of Perl and all that. :)