Forum Moderators: coopster & phranque

Message Too Old, No Replies

Using JSON as a Perl hash

         

csdude55

7:45 pm on Oct 23, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



In the form, I use Javascript's JSON.stringify() to create a string like:

# spaces added for readability
$json = qq~
[
null,
{"0":{},"length":1},

{"0":{},"length":1},

{"name":"20221020_164047.jpg","uuid":"43f07ec4-17a7-4874-bb84-66a0f002f48e"},
{"name":"20221021_144704 (1).jpg","uuid":"71bba099-2616-4415-b420-0d0d16c19c30"}
]
~;


I'm not sure why it gets wrapped in [ ], I guess JSON.stringify() does that? But it's not intentional on my part. I'm also not sure why I get "null" or {"0":{},"length":1} in there, all that I'm intentionally plugging in are the two lines with "name" and "uuid".

I installed the JSON module, and $text = decode_json $json; print Dumper($text); gives me:

$VAR1 = [
undef,
{
'length' => 1,
'0' => {}
},
{
'length' => 1,
'0' => {}
},
{
'name' => '20221020_164047.jpg',
'uuid' => '43f07ec4-17a7-4874-bb84-66a0f002f48e'
},
{
'name' => '20221021_144704 (1).jpg',
'uuid' => '71bba099-2616-4415-b420-0d0d16c19c30'
}
];


From there, how do I access each name and uuid?

phranque

11:16 pm on Oct 23, 2022 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



the square brackets create an array reference.
the constructed array contains 5 items.
the first item in the array is undef and the following 4 items are hash references (created by the curly braces).

i assume you can take it from there...

csdude55

4:54 am on Oct 24, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



i assume you can take it from there...

You would think, wouldn't you? LOL

It took some work, but I finally figured it out:

$str = decode_json $json;

foreach $key (@{$str}) {
if ($key->{'name'}) {
print $key->{'name'} . "\n";
}
}

phranque

7:43 am on Oct 24, 2022 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



You would think, wouldn't you? LOL

LOL

It took some work, but I finally figured it out

excellent!
thanks for showing your work...

csdude55

6:01 pm on Oct 27, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I have a follow up question on this.

At this point I have:

# spaces added for readability
# $json really comes from the query string
$json = qq~
[
{
'name' => '20221020_164047.jpg',
'uuid' => '43f07ec4-17a7-4874-bb84-66a0f002f48e'
},
{
'name' => '20221021_144704 (1).jpg',
'uuid' => '71bba099-2616-4415-b420-0d0d16c19c30'
}
]
~;

$str = decode_json $json;

foreach $key (@{$str}) {
if ($key->{'name'}) {
print $key->{'name'} . "\n";
}
}

but I've discovered that, if decode_json fails then it's a fatal error for the script!

Can you suggest a way to determine whether $json contains at least one valid {'name'} and {'uuid'} before proceeding? I know that I could check via regex, like:

if ($json =~ /name.+=>.+uuid.+=>/si) {
$str = decode_json $json;

foreach $key (@{$str}) {
if ($key->{'name'}) {
print $key->{'name'} . "\n";
}
}
}

but I'm hoping for something that will only return true if the keys / values are valid.

I thought that JSON::is_bool($json)/ would work, but it returns false (or empty) every time so I guess I misunderstand the purpose of it?

Returns true if the passed scalar represents either JSON::true or JSON::false, two constants that act like 1 and 0 respectively and are also used to represent JSON true and false in Perl strings.

[metacpan.org...]

csdude55

8:59 pm on Oct 27, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Update: I also tried if ($str = decode_json $json) { ... } and $str = decode_json $json or die;, but neither prevented a painful death if decode_json failed.

The only solution I'm finding is:

$str = false;
eval { $str = decode_json $json };

if ($str) {
foreach $key (@{$str}) {
if ($key->{'name'}) {
print $key->{'name'} . "\n";
}
}
}

phranque

9:28 pm on Oct 27, 2022 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



using eval creates a new process, so probably not the most efficient solution.

csdude55

12:05 am on Oct 28, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



It would definitely be my last resort, but I can't think of any other alternative :-/ Do you have any other suggestions?

csdude55

5:59 pm on Oct 28, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I discovered that Try::Tiny is installed on the server, I'm not sure if it's part of the default package but I certainly don't remember installing it myself.
[metacpan.org...]

So another option is:

use Try::Tiny;

$str = false;
try { $str = decode_json $json };

but my benchtest found eval { } to be about 10 times faster, so I'm not sure what the advantage to use Try::Tiny would be.

It kinda sucks that there's no way to modify decode_json so that it warns instead of croaks, but it is what it is :-/