CocoRuby
CocoRuby

Reputation: 57

How to remove a JSON object in perl

I am working on a JSON config file (logstash-forwarder) in which I want to add or remove data with a perl script (It is a script used to deploy or undeploy jboss webapps and it could then be used to update logstash forwarder configuration).

I have no problem with adding and modifying the configuration file but I can't find the right way to remove an object.

Here is an example of the config.json file:

{    
    "network" : {
          "timeout" : 15,
          "ssl ca" : "/etc/logstash-forwarder/cert/logstash-forwarder.crt",
          "servers" : [
             "server1@domain:5043",
             "server2@domain:5043"
          ]    },    
    "files" : [
          {
             "fields" : {
                "environment" : "TEST1,TEST23",
                "application" : "application1",
                "type" : "jboss"
             },
             "paths" : [
                "/path/to/application1/logs/*.log"
             ]
          },
          {
             "fields" : {
                "environment" : "TEST2",
                "application" : "application2",
                "type" : "jboss"
             },
             "paths" : [
                "/path/to/application2/logs/*.log"
             ]
          }    
     ]
}

And the part of the code I am using to delete an object (when the webapp is undeployed):

removeLogStashConf
{
    use JSON qw(encode_json decode_json);

    my ( $application ) = @_;

    my $app_path    = "/path/to/$application/*.log";

    local $/;
    open( my $fh, "<", "$Param::logstash_conf_file" );
    my $json = <$fh>;
    close $fh;

    my $data = JSON::decode_json($json); };

    my @files              = @{ $data->{'files'} };
    my $file_level         = undef;

    foreach my $f (@files) {
        my @paths = @{ $f->{"paths"} };
        foreach my $path (@paths) {
            if ( $path eq $app_path ) {
                $file_level         = $f;
            }
        }
    }

    for (keys %$file_level)
    {
        delete $file_level->{$_};
    }


    my $encoded = JSON->new->utf8->pretty->encode($data);
    open( $fh, ">", "$Param::logstash_conf_file" );
    print $fh $encoded;
}

When I try to remove, say, application2, the result I get in config.json file is:

{    
    "network" : {
          "timeout" : 15,
          "ssl ca" : "/etc/logstash-forwarder/cert/logstash-forwarder.crt",
          "servers" : [
             "server1@domain:5043",
             "server2@domain:5043"
          ]    },
    "files" : [
          {
             "fields" : {
                "environment" : "TEST1,TEST23",
                "application" : "application1",
                "type" : "jboss"
             },
             "paths" : [
                "/path/to/application1/logs/*.log"
             ]
          },
          {}    
     ] 
}

How can I get rid of that remaining empy curly brackets ("{}" or "{}," if I remove an application that is not the last of the array) that prevent me to do further parsing and that let me with an untidy config.json file.

I could surely find a solution with a sed but is there something cleaner?

Thank you in advance for your help.

Upvotes: 1

Views: 2408

Answers (1)

Vadim Pushtaev
Vadim Pushtaev

Reputation: 2353

Emptying hash is not enough to delete it from array.

You can use splice or just copy all needed records to a new array:

my $data = JSON::decode_json($json);

my @files = @{ $data->{'files'} };
my @new_files;

foreach my $f (@files) {
    my @paths = @{ $f->{paths} };
    foreach my $path (@paths) {
        unless ( $path eq $app_path ) {
            push @new_files, $f;
        }
    }
}

$data->{files} = \@new_files;

Upvotes: 2

Related Questions