Perl Newbie - Printing value from array - perl

I am brand new to perl. I am trying to grab a string out of some JSON output. My code below works, but seems like there is a smarter way to do this. Here is a sample of the JSON
$VAR1 = '{
"hasDetailRows" : true,
"reportMetadata" : {
"reportFormat" : "TABULAR",
"detailColumns" : [ "SUBJECT", "COMMENT_CREATED_DATE", "CASE_COMMENT_CREATED_BY" ],
"reportBooleanFilter" : null,
"reportFilters" : [ {
"column" : "CASE_COMMENT_CREATED_BY",
"operator" : "equals",
"value" : "Username"
} ],
"aggregates" : [ "RowCount" ],
"groupingsDown" : [ ],
"groupingsAcross" : [ ],
"developerName" : "My_Comments",
"reportType" : {
"type" : "CaseList",
"label" : "Cases"
},
"name" : "My Comments",
"id" : "REDCATED",
"currency" : null
},
"factMap" : {
"T!T" : {
"rows" : [ {
"dataCells" : [ {
"value" : "ID",
"label" : "Description"
}, {
"value" : "2014-02-17T22:01:17Z",
"label" : "2/17/2014 4:01 PM"
}, {
"value" : "USER ID",
"label" : "User Name"
} ]
}`
What I need is that label with the timestamp.
And here is my code
#!/usr/bin/perl
use warnings;
use strict;
use WWW::Mechanize;
use WWW::Salesforce;
use Data::Dumper;
use JSON -support_by_pp;
use 5.010;
use Date::Parse;
my $mech = WWW::Mechanize->new();
$mech->agent('Mozilla/5.0');
# Authenticate first via SOAP interface to get a session ID:
my $sforce = eval { WWW::Salesforce->login(
username => 'REDACTED',
password => 'REDACTED' ); };
die "Could not login to SFDC: $#" if $#;
# Get the session ID:
my $hdr = $sforce->get_session_header();
my $sid = ${$hdr->{_value}->[0]}->{_value}->[0];
#Our request
$mech->add_header( "Authorization" => "OAuth $sid" );
$mech->add_header( "X-PrettyPrint" => '1' );
$mech->get("SOME URL THAT RETURNS JSON");
my $content = $mech->content;
my $json = new JSON;
my $json_text = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($content);
Here is what I have currently that grabs the value that I want from $content. All I need is the first result which is why I am killing the loop after the first run. Everytime I have tried this without a loop I get "Not a HASH reference". So all I need to know is the correct syntax for printing out the value of $timestamp.
foreach my $field(#{$json_text->{factMap}->{'T!T'}->{rows}}){
my $now = time();
my $timestamp = str2time($field->{dataCells}[1]->{'label'});
my $diff = int (($now - $timestamp)/60);
my $current = getLoggingTime();
print $current . " \t";
say "Time since last activity: " . $diff . " minutes!" ;
last;
}
sub getLoggingTime {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
my $nice_timestamp = sprintf ( "%04d-%02d-%02d %02d:%02d:%02d",
$year+1900,$mon+1,$mday,$hour,$min,$sec);
return $nice_timestamp;
}

I don't know what your without-a-loop version looks like, but this should work:
my $timestamp = str2time(
$json_text->{factMap}{'T!T'}{rows}[0]{dataCells}[1]{label}
);
Currently, you're looping over the elements of the array referenced by
$json_text->{factMap}{'T!T'}{rows}
...and stopping at the first entry
$json_text->{factMap}{'T!T'}{rows}[0]
...and dereferencing that to get to
$json_text->{factMap}{'T!T'}{rows}[0]{dataCells}[1]{label}

Related

Perl get array element from mongodb

I wanted to fetch array element and store in Perl variable. If I put 0 in replace of ? in $cur->{Type}[?]->{_id} I'm able to get only one array element but I want all. below is my collection
{
"_id" : ObjectId("5b7fdb050cc3c23478005741"),
"DBName" : "sample",
"DBServerURL" : "mongodb://localhost:27017/",
"Type" : [
{
"_id" : ObjectId("5b801dc963f8c81df83891bd")
},
{
"_id" : ObjectId("5b801dc963f8c81df83891be")
},
{
"_id" : ObjectId("5b801dc963f8c81df83891bf")
},
{
"_id" : ObjectId("5b801dc963f8c81df83891c0")
}
]
}
I'm trying to get ObjectId from all fields
$cursor = $CustColl->find(
{DBName => "sample",DBServerURL => "mongodb://localhost:27017/"},{'_id' => 1, 'Type.$._id' => 1, 'DBServerURL' => 1, 'DBName' => 1}
);
while(my $cur = $cursor->next){
my $cid = "$cur->{_id}" ;
my $jid = "$cur->{Type}[?]->{_id}" ;
my $url = "$cur->{DBServerURL}" ;
my $name = "$cur->{DBName}" ;
print "$cid : $jid : $url : $name\n" ;
}
I wanted an output like below:
5b7fdb050cc3c23478005741 : 5b801dc963f8c81df83891bd : mongodb://localhost:27017/ sample
5b7fdb050cc3c23478005741 : 5b801dc963f8c81df83891be : mongodb://localhost:27017/ sample
5b7fdb050cc3c23478005741 : 5b801dc963f8c81df83891bf : mongodb://localhost:27017/ sample
5b7fdb050cc3c23478005741 : 5b801dc963f8c81df83891c0 : mongodb://localhost:27017/ sample
You are almost there. First, I fixed up your data to make it JSON but that's not a big deal:
my $json = q([{
"_id" : "5b7fdb050cc3c23478005741",
"DBName" : "sample",
"DBServerURL" : "mongodb://localhost:27017/",
"Type" : [
{
"_id" : "5b801dc963f8c81df83891bd"
},
{
"_id" : "5b801dc963f8c81df83891be"
},
{
"_id" : "5b801dc963f8c81df83891bf"
},
{
"_id" : "5b801dc963f8c81df83891c0"
}
]
} ]);
use JSON::XS;
my $perl = decode_json( $json );
That's a JSON array so you can go through it one element at a time. In Perl that shows up as an array reference Using the postfix dereference introduced in v5.20 makes this palatable (but not so hard without it):
while(my $cur = shift $perl->#*){ # or #$perl
my $cid = $cur->{_id} ;
my $url = $cur->{DBServerURL} ;
my $name = $cur->{DBName} ;
foreach my $hash ( $cur->{Type}->#* ) { # or #{ $cur->{Type} }
my $jid = $hash->{_id};
print "$cid : $jid : $url : $name\n" ;
}
}
The trick is that the $jid stuff is in another array and you want to go through those individually. There's a foreach inside the while to do that. It runs once for each of those and outputs the lines.

Extracting sub string using Perl

I have string as follows.
{
"id": "1304145"
,"Name" : "Ravi"
,"State" : "KAR"
,"Comp" : "CTL"
}
,{
"id": "2488398"
,"Name" : "Abhik"
,"State" : "TEL"
,"Comp" : "WFG"
}
,{
"id": "89039487"
,"Name" : "Jana"
,"State" : "ODS"
,"Comp" : "TOT"
}
I want to extract each of the sub-string present in a {} and make a format as follws
ID Name State Comp
1304145 Ravi KAR CTL
2488398 Abhik TEL WFG
89039487 Jana ODS TOT
I tried it, but my scripts are not giving the exact outputs.
Need your help in solving this.
Looks a lot like JSON.
If it is:
#!/usr/bin/env perl
use strict;
use warnings 'all';
use JSON;
my $json = from_json(do{local $/;<DATA>});
my #header = qw ( id Name State Comp );
print join ( "\t", #header ), "\n";
foreach my $row ( #$json ) {
print join ( "\t",#{$row}{#header} ),"\n";
}
__DATA__
[{
"id": "1304145"
,"Name" : "Ravi"
,"State" : "KAR"
,"Comp" : "CTL"
},
{
"id": "2488398"
,"Name" : "Abhik"
,"State" : "TEL"
,"Comp" : "WFG"
}
,{
"id": "89039487"
,"Name" : "Jana"
,"State" : "ODS"
,"Comp" : "TOT"
}
]
Gives:
id Name State Comp
1304145 Ravi KAR CTL
2488398 Abhik TEL WFG
89039487 Jana ODS TOT
That's assuming that you do have JSON though - I had to add [] around your snippet. If it isn't JSON then someone's done something dirty, in creating something that looks a lot like JSON, but that isn't.
If for some reason the data isn't supposed to be JSON, and the keys and values are always enclosed in double-quotes, then you can parse it easily with regular expressions
use strict;
use warnings 'all';
my $s = <<END_STRING;
{
"id": "1304145"
,"Name" : "Ravi"
,"State" : "KAR"
,"Comp" : "CTL"
}
,{
"id": "2488398"
,"Name" : "Abhik"
,"State" : "TEL"
,"Comp" : "WFG"
}
,{
"id": "89039487"
,"Name" : "Jana"
,"State" : "ODS"
,"Comp" : "TOT"
}
END_STRING
my #data = map { { /"([^"]*)"/g } } $s =~ /\{[^{}]*\}/g;
my $fmt = "%-11s %-7s %-7s %s\n";
printf $fmt, qw/ ID Name State Comp /;
for my $item ( #data ) {
printf $fmt, #{$item}{qw/ id Name State Comp /};
}
output
ID Name State Comp
1304145 Ravi KAR CTL
2488398 Abhik TEL WFG
89039487 Jana ODS TOT

Copying Array elements to Hash

I have an array of Hashes with the following structure:
#fields
(
{
"id" => "Name",
"type" => "Text",
"value" = undef,
},
{
"id" => "DOB",
"type" => "Date",
"value" = undef,
},
);
and I have an array with the following elements:
#data = ("John", "10/10/1970");
What wold be the best way to copy the elements of the #data to #fields to get the following without having to iterate and use array indices.
#fields
(
{
"id" => "Name",
"type" => "Text",
"value" = "John",
},
{
"id" => "DOB",
"type" => "Date",
"value" = "10/10/1970",
},
);
A hash slice would have worked if this was within a single hash reference. However, since you have to populate a specific field across multiple hash references, a loop will be needed.
use List::Util 'min';
$fields[$_]->{value} = $data[$_] for 0 .. min( $#fields, $#data );
Perhaps you should make #fields into a hash instead, which would allow you to easily retrieve a field by name.
use warnings;
use strict;
my %fields =
(
Name => {
type => "Text",
value => undef,
},
DOB => {
type => "Date",
value => undef,
},
);
my #data = ("John", "10/10/1970");
$fields{Name}->{value} = $data[0];
$fields{DOB}->{value} = $data[1];
use Data::Dumper;
print Dumper %fields;

Perl and MongoDB: Inserting Array of Objects into Key-Value Pairs

I'd like to insert into my MongoDB using perl the following BSON structure:
{"name" : "BOB", "stuff" : [{"area1": [1,2,3,4,5]}, {"area2": [5,6,7,8,9]}]}
But have had a hard time finding a good example of this. I tried the following:
#!/usr/bin/perl
use MongoDB;
use MongoDB::Database;
use MongoDB::OID;
my $conn = MongoDB::Connection->new;
my $db = $conn->test;
my $users = $db->real_time10;
$users->insert
({
"name" => "BOB",
"stuff" =>
"area1" => [1,2,3,4,5],
"area2" => [5,6,7,8,9]
});
Which grossly outputs upon query in the mongo shell:
db.real_time10.find()
{ "_id" : ObjectId("4fc912fa000207ec08000000"), "ARRAY(0xa5bdd4)" : "area2", "A
RAY(0x2f2e844)" : null, "name" : "BOB", "stuff" : "area1" }
What is going on? Is there a simple way to do this?
My dream/desired output would be:
> db.real_time10.find()
{ "_id" : ObjectId("4fc912fa000207ec08000000"), "stuff" : {"area1" : [1,2,3,4,5],
"area2": [5,6,7,8,9]}, "name" : "BOB" }
Your missing your anonymous-array-constructor (square-brackets) in your example code - but including them in your BSON example. To get your desired output try:
$users->insert({
"name" => "BOB",
"stuff" => {
"area1" => [1,2,3,4,5],
"area2" => [5,6,7,8,9]
}
});
By excluding the array constructor it builds up a hash with the supplied array key, value pairs so it would be parsed as the following (which matches your data-dump):
{
"name" => "BOB",
"stuff" => "area1",
[1,2,3,4,5] => "area2",
[5,6,7,8,9] => undef
}
Note: an array-ref in scalar context will be seen as a string like "ARRAY(0x6052b8)"
Ah, it's this:
#!/usr/bin/perl
use MongoDB;
use MongoDB::Database;
use MongoDB::OID;
my $conn = MongoDB::Connection->new;
my $db = $conn->test;
my $users = $db->real_time10;
$users->insert({
"name" => "BOB",
"stuff" =>
{"area1" => [1,2,3,4,5],
"area2" => [5,6,7,8,9]}
});
This outputs:
{ "_id" : ObjectId("4fc91f110064e9d40b000000"), "name" : "BOB", "stuff" : { "are
a2" : [ 5, 6, 7, 8, 9 ], "area1" : [ 1, 2, 3, 4, 5 ] } }

How can we identify all the modules belongs to a given distribution

How can we identify all the modules belongs to a given distribution.
e.g. the XML::LibXML distribution provides a set of following modules
https://metacpan.org/release/XML-LibXML
How can we get this list either through cpan/ppm or through any standard per packages.
Actually we are writing a unit test framework for our code written in Perl. To verify the module, we need a way to find the distribution name for a given module name.
The MetaCPAN API provides a solution to this problem with a JSON web service (http://api.metacpan.org).
It's easy to try different queries using curl on the command line or via the web form at http://explorer.metacpan.org/
If you know the name of the release you're searching for,
you can do a query like this to get a list of module names:
/module/_search
{
"query" : { "match_all" : {} },
"size" : 1000,
"fields" : [ "module.name" ],
"filter" : {
"and": [
{ "term" : { "module.authorized" : true } },
{ "term" : { "module.indexed" : true } },
{ "term" : { "release" : "XML-LibXML-1.95" } },
{ "term" : { "status" : "latest" } }
]
}
}
You could also substitute "release": "XML-LibXML-1.95" with "distribution": "XML-LibXML".
If you are starting with a module name and need to determine the name of the release first, try this:
/module/_search
{
"query" : { "match_all" : {} },
"size" : 1000,
"fields" : [ "release", "distribution" ],
"filter" : {
"and": [
{ "term" : { "module.name" : "XML::LibXML" } },
{ "term" : { "status" : "latest" } }
]
}
}
That query syntax is the ElasticSearch DSL since the api uses ElasticSearch to index the data.
To do query from perl there is a MetaCPAN::API
module, though I have not used it myself.
Since it's just a web request you can use LWP or any other HTTP module.
You might alo want to check out the
ElasticSearch and
ElasticSearch::SearchBuilder
modules which provide a more full perl interface to querying an ElasticSearch database.
Here's a full example in perl using LWP:
use JSON qw( encode_json decode_json );
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
my $res = $ua->post("http://api.metacpan.org/module/_search",
Content => encode_json({
query => { match_all => {} },
size => 1000,
# limit reponse text to just the module names since that's all we want
fields => ['module.name'],
filter => {
and => [
{ term => { "module.authorized" => 1 } },
{ term => { "module.indexed" => 1 } },
{ term => { "distribution" => "XML-LibXML" } },
{ term => { "status" => "latest" } }
]
}
})
);
my #modules =
# this can be an array (ref) of module names for multiple packages in one file
map { ref $_ ? #$_ : $_ }
# the pieces we want
map { $_->{fields}{'module.name'} }
# search results
#{ decode_json($res->decoded_content)->{hits}{hits} };
print join "\n", sort #modules;
For more help visit #metacpan on irc.perl.org,
or check out the wiki at https://github.com/CPAN-API/cpan-api/wiki.
If you explain a little more what you are doing and/or trying to achive you might find other ways to do it.