Home > front end >  how to parse complex JSON in perl
how to parse complex JSON in perl

Time:06-08

I have the following JSON content and I am trying to parse it by using perl (use JSON qw( decode_json );

here you have the complete JSON content,

{
  "page": {
    "currentPage": 1,
    "totalPages": 1,
    "pageSize": 45
  },
  "networkelements": [
    {
      "name": "aRestPM",
      "alias": "",
      "networkAddresses": [
        {
          "address": "135.244.37.111",
          "port": 443,
          "restResourceId": "135.244.37.111:443",
          "connectionProtocol": "ADAPTER_MANAGED"
        },
        {
          "address": "10.206.198.182",
          "port": 443,
          "restResourceId": "10.206.198.182:443",
          "connectionProtocol": "ADAPTER_MANAGED"
        }
      ],
      "adapter": {
        "name": "Simple RestService V1.0",
        "version": "19.0.SR5a-STD-0.50_PM-SNAPSHOT"
      },
      "vendor": "Simple",
      "model": "RestService",
      "version": "V1.0",
      "creationTime": "2022-04-07T20:32:22.368-0000",
      "agentGroupName": "DefaultAgentGroup",
      "connectivityState": "IN_CONTACT_CONDITIONAL",
      "interfaces": [
        {
          "name": "REST",
          "networkAddresses": [
            {
              "address": "135.244.37.111",
              "port": 443
            },
            {
              "address": "10.206.198.182",
              "port": 443
            }
          ],
          "sessionCredentialAAAServer": "AAA",
          "sessionCredential": {
            "userId": "dummy"
          },
          "adminState": "ON_DEMAND",
          "sessionAddresses": {},
          "additionalAttributes": {}
        }
      ],
      "customAttributes": {},
      "managementState": "MANAGED",
      "emsServer": "No"
    },
    {
      "name": "aRestPM_443",
      "alias": "",
      "networkAddresses": [
        {
          "address": "10.154.74.91",
          "port": 443,
          "restResourceId": "10.154.74.91:443",
          "connectionProtocol": "ADAPTER_MANAGED"
        }
      ],
      "adapter": {
        "name": "Simple RestService V1.0",
        "version": "19.0.SR5a-STD-0.50_PM-SNAPSHOT"
      },
      "vendor": "Simple",
      "model": "RestService",
      "version": "V1.0",
      "creationTime": "2022-05-16T13:06:01.928-0000",
      "agentGroupName": "DefaultAgentGroup",
      "connectivityState": "IN_CONTACT_CONDITIONAL",
      "interfaces": [
        {
          "name": "REST",
          "networkAddresses": [
            {
              "address": "10.154.74.91",
              "port": 443
            }
          ],
          "sessionCredential": {
            "userId": "dummy"
          },
          "adminState": "ON_DEMAND",
          "sessionAddresses": {},
          "additionalAttributes": {}
        }
      ],
      "customAttributes": {},
      "managementState": "MANAGED",
      "emsServer": "No"
    }
  ]
}

I need to print name from networkelements array and address and ip from networkAddresses

the given json is in $keycloak_response

$decoded = decode_json($keycloak_response);
my @networkelements = @{ $decoded->{'networkelements'} };
my @net             = @{ $decoded->{"networkelements"}[0]{"networkAddresses"} };
#print Dumper \@net;

foreach my $ne ( @networkelements ) {
    $ne_name = $ne->{"name"};
    $decoded2 = decode_json($ne);
    my @net = @{ $decoded2->{"networkAddresses"} };
    foreach my $ne ( @net) {
        print $ne_name . "," . $ne->{"address"} . "," . $ne->{"port"} . "\n";
    }
}

expected result is

aRestPM,135.244.37.111,443
aRestPM,10.206.198.182,443
aRestPM_443,10.154.74.91,443

I would really appreciate any advice.

Thanks

CodePudding user response:

decode_json( $ne ) is wrong since $ne doesn't contain JSON.

for my $networkelement (@{ $decoded->{ networkelements } }) {
   my $name = $networkelement->{ name };

   for my $networkAddress (@{ $networkelement->{ networkAddresses } }) {
      my $address = $networkAddress->{ address };
      my $port    = $networkAddress->{ port    };

      say join ",", $name, $address, $port;
   }
}

You created needless copies of arrays, which I avoided. And I properly scoped my variables. Always use use strict; use warnings;!

CodePudding user response:

JSON data should be decoded only once and you get fully restored structure of the data.

Reference: from_json

It does not require to create intermediary variables, you have full direct access to data of interest -- use it to your advantage.

Usage of map gives you access to elements of an array what allows to avoid loop.

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

use JSON;

my $json = do { local $/; <DATA> };
my $data = from_json($json);

for my $e ( @{$data->{'networkelements'}} ) {
    say join ',', $e->{name},$_->@{qw/address port/} for @{$e->{networkAddresses}};
}

exit 0;

__DATA__
{
  "page": {
    "currentPage": 1,
    "totalPages": 1,
    "pageSize": 45
  },
  "networkelements": [
    {
      "name": "aRestPM",
      "alias": "",
      "networkAddresses": [
        {
          "address": "135.244.37.111",
          "port": 443,
          "restResourceId": "135.244.37.111:443",
          "connectionProtocol": "ADAPTER_MANAGED"
        },
        {
          "address": "10.206.198.182",
          "port": 443,
          "restResourceId": "10.206.198.182:443",
          "connectionProtocol": "ADAPTER_MANAGED"
        }
      ],
      "adapter": {
        "name": "Simple RestService V1.0",
        "version": "19.0.SR5a-STD-0.50_PM-SNAPSHOT"
      },
      "vendor": "Simple",
      "model": "RestService",
      "version": "V1.0",
      "creationTime": "2022-04-07T20:32:22.368-0000",
      "agentGroupName": "DefaultAgentGroup",
      "connectivityState": "IN_CONTACT_CONDITIONAL",
      "interfaces": [
        {
          "name": "REST",
          "networkAddresses": [
            {
              "address": "135.244.37.111",
              "port": 443
            },
            {
              "address": "10.206.198.182",
              "port": 443
            }
          ],
          "sessionCredentialAAAServer": "AAA",
          "sessionCredential": {
            "userId": "dummy"
          },
          "adminState": "ON_DEMAND",
          "sessionAddresses": {},
          "additionalAttributes": {}
        }
      ],
      "customAttributes": {},
      "managementState": "MANAGED",
      "emsServer": "No"
    },
    {
      "name": "aRestPM_443",
      "alias": "",
      "networkAddresses": [
        {
          "address": "10.154.74.91",
          "port": 443,
          "restResourceId": "10.154.74.91:443",
          "connectionProtocol": "ADAPTER_MANAGED"
        }
      ],
      "adapter": {
        "name": "Simple RestService V1.0",
        "version": "19.0.SR5a-STD-0.50_PM-SNAPSHOT"
      },
      "vendor": "Simple",
      "model": "RestService",
      "version": "V1.0",
      "creationTime": "2022-05-16T13:06:01.928-0000",
      "agentGroupName": "DefaultAgentGroup",
      "connectivityState": "IN_CONTACT_CONDITIONAL",
      "interfaces": [
        {
          "name": "REST",
          "networkAddresses": [
            {
              "address": "10.154.74.91",
              "port": 443
            }
          ],
          "sessionCredential": {
            "userId": "dummy"
          },
          "adminState": "ON_DEMAND",
          "sessionAddresses": {},
          "additionalAttributes": {}
        }
      ],
      "customAttributes": {},
      "managementState": "MANAGED",
      "emsServer": "No"
    }
  ]
}

Output

aRestPM,135.244.37.111,443
aRestPM,10.206.198.182,443
aRestPM_443,10.154.74.91,443

Note: printf can generate aligned output

printf "%-12s %-15s %d\n", $e->{name},$_->{address},$_->{port} for @{$e->{networkAddresses}};

Output

aRestPM      135.244.37.111  443
aRestPM      10.206.198.182  443
aRestPM_443  10.154.74.91    443
  • Related