Perl add content to JSON data after processing

Viewed 453

I have a json file, which I am processing using perl JSON module.

Once I process it, I want to insert some content to in it.

Here is my input json file:

{
  "sequence" : [ 
  {
    "type" : "event",
    "attribute" : {     
      "contentText" : "Test Content",
      "contentNumber" : "11"
    }
  } 
  ],
  "current" : 0,
  "next" : 1
}

And below is my script:

#!/usr/bin/perl

use strict;
use warnings;

use JSON;
use Data::Dumper;

my $needed = 2;
my $filename = "test_file.json";

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};

print Dumper($aref);

my $number;

for my $element (@$aref) {
    $number = $element->{attribute}->{contentNumber}."\n";
}

print "Number:$number\n";

my $total = $number + $needed;

foreach my $each_number ($number+1..$total){
    print $each_number."\n";
}

print Dumper $data;

So what I needed over here is fetch contentNumber from given json file and increment value by 1 till $needed is mentioned and form a new json file.

And finally it should form JSON file which should have content like below: Where whatever $needed variable value is mentioned that many times the json should form the data including the initial data.

{
  "sequence" : [ 
  {
    "type" : "event",
    "attribute" : {     
      "contentText" : "Test Content",
      "contentNumber" : "11"
    }
  },
  {
    "type" : "event",
    "attribute" : {     
      "contentText" : "Test Content",
      "contentNumber" : "12"
    }
  },
  {
    "type" : "event",
    "attribute" : {     
      "contentText" : "Test Content",
      "contentNumber" : "13"
    }
  }
  ],
  "current" : 0,
  "next" : 1
}

I was thinking to push the data in foreach loop. But no clue how we can put it in data object which should give me an output with json format.

1 Answers

From the desired output it appears that you need the hashref which is in sequence's array. Then you need to add $needed number of its copies to that array, with contentNumber incremented in each. (I can't reconcile that with the shown code and I'll go with the desired output, which seems clear.)

Don't forget that the copies must be deep copies;† here I use dclone from Storable for that.

use Storable qw(dclone);

...

my $seq_href = dclone( $data->{sequence}[0] );

for (1..$needed) { 
    ++$seq_href->{attribute}{contentNumber};
    push @{$data->{sequence}}, dclone( $seq_href );
}

my $new_json_string = $json->encode($data);  # then write it to file

This produces the desired output JSON in my tests.


† A variable or data structure containing references cannot be copied into a new, independent one by merely assigning

my @copy = @ary;   # oups ... any references in there?

The problem is that when the elements that are references in @ary are copied into @copy then those elements in @copy, being the same references, point to same memory locations as the ones from @ary! So @copy and @ary are by no means independent -- they share data.

Sometimes that may be desired but if we need an independent copy, like in this problem, then we need to follow those references all the way and actually copy the data so that the copied structure indeed has its own data. And there are modules that do that of course.

Complex (nested) data structures by definition have references for elements and so we certainly can't get independent copies by one top-level assignment.

This is a very skinny description of a potentially sneaky and subtle bug. I'd suggest to read up more on it. One resource that comes up is an Effective Perler article.

Related