Parsing simple JSON array in Perl [duplicate] - json

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Parse perl array
I'm trying to edit an old perl script and I'm a complete beginner.
The request from the server returns as:
$result = {
"data": {
"translations": [
{
"translatedText": "Halloween"
}
]
}
}
How can I parse this JSON string to grab:
$result = "Halloween"
Thanks.

#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use JSON;
my $json = '{
"data": {
"translations": [
{
"translatedText": "Halloween"
}
]
}
}';
my $data = decode_json($json);
say $data->{data}{translations}[0]{translatedText};

There are uncountable JSON parsing modules available; the most standard-like one is JSON.

You could take the easy way and do it like this (didn't check if this compiles):
my $translatedText = ""
if ($result =~ /"translatedText": "(.+?)"/)
{
$translatedText = $1;
}
if you want to parse for more items and different json strings then you should use some perl module (there are a few avaialble)

Related

Perl LWP::UserAgent parse response JSON

I am using the LWP::UserAgent module to issue a GET request to one of our APIs.
#!/usr/bin/perl
use strict;
use warning;
use LWP::UserAgent;
use Data::Dumper;
my $ua = LWP::UserAgent->new;
my $request = $ua->get("http://example.com/foo", Authorization => "Bearer abc123", Accept => "application/json" );
print Dumper $request->content;
The request is successful. Dumper returns the following JSON.
$VAR1 = '{
"apiVersion": "v1",
"data": {
"ca-bundle.crt": "-----BEGIN CERTIFICATE-----abc123-----END CERTIFICATE-----\\n"
},
"kind": "ConfigMap",
"metadata": {
"creationTimestamp": "2021-07-16T17:13:01Z",
"labels": {
"auth.openshift.io/managed-certificate-type": "ca-bundle"
},
"managedFields": [
{
"apiVersion": "v1",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:data": {
".": {},
"f:ca-bundle.crt": {}
},
"f:metadata": {
"f:labels": {
".": {},
"f:auth.openshift.io/managed-certificate-type": {}
}
}
},
"manager": "cluster-kube-apiserver-operator",
"operation": "Update",
"time": "2021-09-14T17:07:39Z"
}
],
"name": "kube-control-plane-signer-ca",
"namespace": "openshift-kube-apiserver-operator",
"resourceVersion": "65461225",
"selfLink": "/api/v1/namespaces/openshift-kube-apiserver-operator/configmaps/kube-control-plane-signer-ca",
"uid": "f9aea067-1234-5678-9101-9d4073f5ae53"
}
}';
Let's say I want to print the value of the apiVersion key, which should print v1.
print "API Version = $request->content->{'apiVersion'} \n";
The following is being printed. I am not sure how to print the value v1. Since HTTP::Response is included in the output, I suspect I might have to use the HTTP::Response module?
API Version = HTTP::Response=HASH(0x2dffe80)->content->{'apiVersion'}
Perl doesn't expand subroutine calls in a double-quoted string.
print "API Version = $request->content->{'apiVersion'} \n";
In this line of code, content() is a subroutine call. So Perl sees this as:
print "API Version = $request" . "->content->{'apiVersion'} \n";
And if you try to print most Perl objects, you'll get the hash reference along with the name of the class - hence HTTP::Response=HASH(0x2dffe80).
You might think that you just need to break up your print() statement like this:
print 'API Version = ', $request->content->{'apiVersion'}, "\n";
But that's not going to work either. $request->content doesn't return a Perl data structure, it returns a JSON-encoded string. You need to decode it into a data structure before you can access the individual elements.
use JSON;
print 'API Version = ', decode_json($request->content)->{'apiVersion'}, "\n";
But it might be cleaner to do the decoding outside of the print() statement.
use JSON;
my $data = decode_json($request->content);
In which case you can go back to something more like your original code:
print "API Version = $data->{'apiVersion'} \n";
The JSON content must be decoded first. There are several modules for that, like JSON:
use JSON;
# ...
my $href = decode_json $request->content;
And then use it like a normal hash reference: $href->{apiVersion}

looping through json in perl

I'm trying to grab some information out of a json export from Ping. My rusty Perl skills are failing me as I'm getting lost in the weeds with the dereferencing. Rather than bang my head against the wall some more I thought I'd post a question since all the google searches are leading here.
My understanding is that decode_json converts items into an array of hashes and each hash has strings and some other arrays of hashes as contents. This seems to bear out when attempting to get to an individual string value but only if I manually specify a specific array element. I can't figure out how to loop through the items.
The JSON comes back like this:
{
"items":[
{
#lots of values here are some examples
"type": "SP",
"contactInfo": {
"company": "Acme",
"email": "john.doe#acme.com"
}
]
}
I had no problems getting to actual values
#!/usr/bin/perl
use JSON;
use Data::Dumper;
use strict;
use warnings;
use LWP::Simple;
my $json;
{
local $/; #Enable 'slurp' mode
open my $fh, "<", "idp.json";
$json = <$fh>;
close $fh;
}
my $data = decode_json($json);
#array print $data->{'items'};
#hash print $data->{'items'}->[0];
#print $data->{'items'}->[0]->{'type'};
But, I can't figure out how to iterate through the array of items. I've tried for and foreach and various combinations of dereferencing, and it keeps telling me that the value I'm looping thru is still an array. If $data->{'items'} is an array, then presumably I should be able to do some variation of
foreach my $item ($data->{'items'})
or
my #items = $data->{'items'};
for (#items)
{
# stuff
}
But, I keep getting arrays back and I have to add in the ->[0] to get to a specific value.
$data->{'items'} is a reference to an array (of hash references). You need to dereference it, with #{ }:
use JSON;
use strict;
use warnings;
my $json;
{
local $/; #Enable 'slurp' mode
$json = <DATA>;
}
my $data = decode_json($json);
for my $item (#{ $data->{items} }) {
print "$item->{type}\n";
}
__DATA__
{
"items":[
{
"type": "SP",
"contactInfo": {
"company": "Acme",
"email": "john.doe#acme.com"
}
}
]
}
Output:
SP

Perl json keys with spaces [duplicate]

This question already has answers here:
Which Perl module would you recommend for JSON manipulation?
(6 answers)
Closed 2 years ago.
how can i parse perl json object which has spaces in its keys
{
"abc" : [
"lmn" : {
"Ab Cd" : "Xy Zw",
"Ef Gh" : "Pq Rs",
}
]
}
By definition, one parses JSON using a JSON parser. There exists multiple JSON parsers on CPAN, including Cpanel::JSON::XS. It handles keys with spaces in them without issue, as should every other JSON parser.
Note that what you have isn't JSON. I'm assuming the errors are typos since you asked about JSON.
Spaces in a key will present no problems at all to any JSON parser.
There are, however, two problems in your JSON that will cause problems for any parser. Others have noted the extra comma after "Pq Rs", but you also have an array that contains a key/value pair (with the key "lnm") which needs to be inside an object.
Originally, I just removed the comma and ran this code:
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
use JSON;
my $json = '{
"abc" : [
"lmn" : {
"Ab Cd" : "Xy Zw",
"Ef Gh" : "Pq Rs"
}
]
}';
my $data = decode_json($json);
say Dumper $data;
This gives an error:
, or ] expected while parsing array, at character offset 28 (before ": {\n "Ab C...")
I fixed it, by inserting { ... } around the lnm object.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
use JSON;
my $json = '{
"abc" : [ {
"lmn" : {
"Ab Cd" : "Xy Zw",
"Ef Gh" : "Pq Rs"
}
} ]
}';
my $data = decode_json($json);
say Dumper $data;
And then I got this output:
$VAR1 = {
'abc' => [
{
'lmn' => {
'Ab Cd' => 'Xy Zw',
'Ef Gh' => 'Pq Rs'
}
}
]
};
Which is, I think, what you are expecting.

accessing parsed json data in perl

I have the following json data in a string $json:
{
"results": [{
"geometry": {
"location": {
"lat": 37.4224764,
"lng": -122.0842499
},
},
}]
}
I use the following to decode my JSON data.
my $decoded_json = decode_json( $json );
And I'm attempting at retrieving the latitude here:
my $lat=$decoded_json->{results}->{geometry}{location}{lat};
And Here:
my $lat=$decoded_json->{results}->{geometry}->{location}->{lat};
I'd like to know how to retrieve the lat and lng from this decoded data.
There's an array in your JSON, but no array dereference in your code. In other words, you completely overlooked the [ ... ] in the JSON. You need to specify which of the results you want. In the example in question, there is only one, so you could use the following:
my $loc = $decoded_json->{results}[0]{geometry}{location};
my $lat = $loc->{lat};
my $lng = $loc->{lng};
Of course, the whole point of using an array of results is that the number of results might vary. You will probably need a loop.
for my $result (#{ $decoded_json->{results} }){
my $loc = $result->{geometry}{location};
my $lat = $loc->{lat};
my $lng = $loc->{lng};
...
}
About the arrows...
my $lat = $decoded_json->{results}[0]{geometry}{location}{lat};
is short for
my $lat = $decoded_json->{results}->[0]->{geometry}->{location}->{lat};
When the -> is between {...} or [...], and {...} or [...], it can be omitted.
That's why there's no difference between
$result->{geometry}{location}{lat};
$result->{geometry}{location}->{lat};
( $result->{geometry}{location} )->{lat}; # Can't be omitted here.
my $loc = $result->{geometry}{location};
my $lat = $loc->{lat}; # Can't be omitted here.
Given the name of the key, "results", it is natural to expect there might be times where you get more than one result. The following will give you the coordinates for all results returned:
for my $r (#{ $decoded_json->{results} }) {
my ($lat, $lng) = #{ $r->{geometry}{location} }{qw(lat lng)}
# do something with coordinates
}
With recent Perl versions, you can re-write that as:
for my $r ($decoded_json->{results}->#*) {
my ($lat, $lng) = $r->{geometry}{location}->#{qw(lat lng)};
# do something with coordinates
}
Once again, decode_json gives you a Perl data structure. The fact that the contents of that structure were constructed by parsing a JSON document are completely irrelevant to what you do with it.
Working example (Cpanel::JSON::XS chokes on your JSON):
#!/usr/bin/env perl
use utf8;
use strict;
use warnings;
use JSON::MaybeXS qw( decode_json );
my $json_string = <<EO_JSON;
{
"results": [{
"geometry": {
"location": {
"lat": 37.4224764,
"lng": -122.0842499
}
}
}]
}
EO_JSON
my $data = decode_json($json_string);
for my $r (#{ $data->{results} }) {
my ($lat, $lng) = #{ $r->{geometry}{location} }{qw(lat lng)};
print "($lat,$lng)\n";
}
for my $r ($data->{results}->#*) {
my ($lat, $lng) = $r->{geometry}{location}->#{qw(lat lng)};
print "($lat,$lng)\n";
}

Parsing JSON Data::Dumper output array in Perl

I'm trying to edit an old perl script and I'm a complete beginner. The request from the server returns as:
$VAR1 = [
{
'keywords' => [
'bare knuckle boxing',
'support group',
'dual identity',
'nihilism',
'support',
'rage and hate',
'insomnia',
'boxing',
'underground fighting'
],
}
];
How can I parse this JSON string to grab:
$keywords = "bare knuckle boxing,support group,dual identity,nihilism,support,rage and hate,insomnia,boxing,underground fighting"
Full perl code
#!/usr/bin/perl
use LWP::Simple; # From CPAN
use JSON qw( decode_json ); # From CPAN
use Data::Dumper; # Perl core module
use strict; # Good practice
use warnings; # Good practice
use WWW::TheMovieDB::Search;
use utf8::all;
use Encode;
use JSON::Parse 'json_to_perl';
use JSON::Any;
use JSON;
my $api = new WWW::TheMovieDB::Search('APIKEY');
my $img = $api->type('json');
$img = $api->Movie_imdbLookup('tt0137523');
my $decoded_json = decode_json( encode("utf8", $img) );
print Dumper $decoded_json;
Thanks.
Based on comments and on your recent edit, I would say that what you are asking is how to navigate a perl data structure, contained in the variable $decoded_json.
my $keywords = join ",", #{ $decoded_json->[0]{'keywords'} };
say qq{ #{ $arrayref->[0]->{'keywords'} } };
As TLP pointed out, all you've shown is a combination of perl arrays/hashes. But you should look at the JSON.pm documentation, if you have a JSON string.
The result you present is similar to json, but the Perl-variant of it. (ie => instead of : etc). I don't think you need to look into the json part of it, As you already got the data. You just need to use Perl to join the data into a text string.
Just to eleborate on the solution to vol7ron :
#get a reference to the list of keywords
my $keywords_list = $decoded_json->[0]{'keywords'};
#merge this list with commas
my $keywords = join(',', #$keywords_list );
print $keywords;