vkk05
vkk05

Reputation: 3222

Parsing JSON data in Perl

I am parsing JSON data which is in .json file. Here I have 2 formats of JSON data files.

I could parse first JSON file - file is shown below:

file1.json

{
  "sequence" : [ {
    "type" : "type_value",
     "attribute" : {
      "att1" : "att1_val",
      "att2" : "att2_val",
      "att3" : "att3_val",
      "att_id" : "1"
    }
  } ],
  "current" : 0,
  "next" : 1
}

Here is my script:

#/usr/lib/perl
use strict;
use warnings;
use Data::Dumper;

use JSON;

my $filename = $ARGV[0]; #Pass json file as an argument
print "FILE:$filename\n";

my $json_text = do {
   open(my $json_fh, "<:encoding(UTF-8)", $filename)
      or die("Can't open \$filename\": $!\n");
   local $/;
   <$json_fh>
};

my $json = JSON->new;
my $data = $json->decode($json_text);

my $aref = $data->{sequence};

my %Hash;

for my $element (@$aref) {
    my $a = $element->{attribute};
    next if(!$a);

    my $aNo = $a->{att_id};
    $Hash{$aNo}{'att1'}     = $a->{att1};
    $Hash{$aNo}{'att2'}     = $a->{att2};
    $Hash{$aNo}{'att3'}     = $a->{att3};
}

print Dumper \%Hash;

Everything is getting stored in %Hash and when I print Dumper of the %Hash I am getting following result.

$VAR1 = {
          '1' => {
                   'att1' => 'att1_val',
                   'att2' => 'att2_val',
                   'att3' => 'att3_val'
                 }
        };

But when I parse second set of JSON file, I am getting empty hash by using the above script. Output:

$VAR1 = {};

Here is the JSON file - file2.json

{
  "sequence" : [ {
    "type" : "loop",
    "quantity" : 8,
    "currentIteration" : 0,
    "sequence" : [ {
      "type" : "type_value",
      "attribute" : {
        "att1" : "att1_val",
        "att2" : "att2_val",
        "att3" : "att3_val",
        "att_id" : "1"
      }
    } ]
  } ]
}

We can see two sequence in above JSON data file, which is causing the problem. Can somebody tell me what I am missing in the script inorder to parse file2.json.

Upvotes: 0

Views: 1068

Answers (2)

Polar Bear
Polar Bear

Reputation: 6798

Please see the following code if it fits your requirements

#!/usr/bin/env perl
#
# vim: ai:sw=4:ts=4
#

use strict;
use warnings;
use feature 'say';

use Data::Dumper;
use JSON;

my $debug = 0;          # debug flag

my $filename = shift;   # Pass json file as an argument

say "FILE: $filename";

open(my $json_fh, "<:encoding(UTF-8)", $filename)
    or die("Can't open \$filename\": $!\n");

my $json_data = do { local $/; <$json_fh> };

close $json_fh;

my $json = JSON->new;
my $data = $json->decode($json_data);

say Dumper($data) if $debug;

my $data_ref;
my %Hash;

$data_ref = $data->{sequence}[0]{attribute}
            if $filename eq 'file1.json';
$data_ref = $data->{sequence}[0]{sequence}[0]{attribute}
            if $filename eq 'file2.json';

say Dumper($data_ref) if $debug;

my @fields = qw/att1 att2 att3/;
my $aNo = $data_ref->{att_id};
my %data_hash;

@data_hash{@fields} = $data_ref->{@fields};
$Hash{$aNo} = \%data_hash;

say Dumper(\%Hash);

Upvotes: 0

H&#229;kon H&#230;gland
H&#229;kon H&#230;gland

Reputation: 40718

One possibility might be to check the type field to differentiate between the two file formats:

# [...]
for my $element (@$aref) {
    if ( $element->{type} eq "loop" ) {
        my $aref2 = $element->{sequence};
        for my $element2 ( @$aref2 ) {
            get_attrs( $element2, \%Hash );
        }
    }
    else {
        get_attrs( $element, \%Hash );
    }
}

sub get_attrs {
    my ( $element, $hash ) = @_;

    my $a = $element->{attribute};
    return if(!$a);

    my $aNo = $a->{att_id};
    $hash->{$aNo}{'att1'}     = $a->{att1};
    $hash->{$aNo}{'att2'}     = $a->{att2};
    $hash->{$aNo}{'att3'}     = $a->{att3};
}

Upvotes: 2

Related Questions