My first thought was a simple "search and replace of the underlying JSON code, inspecting it line by line. That will not work as the same "keyword" could be used in various places, but only one specific line needs to be changed.
Then I thought, read the existing data in, create a new entry, push the data into that block, and then delete the original key. The former works … but leaves the original and all its data intact.
Here is a simplified version (don’t think 500+ lines would be appreciated):
{
project 1:{
ad_campaign:{
ad_1{
data1,
data2
},
ad_2{
data1,
data2
}
}
}
project 2:{
ad_campaign:{
ad_1{
data1,
data2
}
ad_201{
data1,
data2
}
}
}
}
The "data" entries are 6 lines per ad, and there could be dozens of ads per project, and dozens of projects !!
They want to change Projec1 "ad_1" to "ad_101"
As you can see, both projects have ads named "ad_1", so a simple search and replace of the underlying text code file is a no-go.
If I use $project1->{"ad_campaign"}, I can get all the data. If I then use: $project1->{"ad_campaign"}=$new_ad_id … it creates a new section (which I =could= then copy the data line – by – line) … but I still cannot get rid of the original "ad_1" entry! ($project1->{"ad_campaign"}->{"ad_1"} =null (no bareword allowed) / "null" / "" have no effect – even when trying to remove the internal data first. That could result in data1:”,data2:” etc)
What I really need is a way to do $customer1->{"ad_campaign"}->{"new_ad_id"} to simply change that third key. (I’ve Googled "change" / "replace" JSON key, but no results … especially as I am using PERL)
One more "spanner in the works"; the file gets saved as a single line, (Using JSON::PP The "pretty" seems to add too many spaces – tab indents would seem better) so would be difficult to break apart, and do a line by line scan anyway. (Another idea was to reiterate through file, set a flag once hit "customer1", another loop, and another flag for "ad_campaign", and then final loop seeking "ad_1". Seems a bit inefficient … plus all the decoded data is in a hash anyway!)
Please bear in mind, I have simplified this code. Between "Project1" and "ad_campaign" could be another 50 key:value pairs PER PROJECT
There is possibly some simple solution finding / changing the value via a hash "argument" … but I’ve yet to find it!
- Somewhere else I read: delete $JSON->{"project1"}->{"ad_campaign"}->{"ad_id"} but that didn’t delete the original either!
Just had a closing thought: Maybe I could do something like "indexOf" to locate project1/ad_campaign etc, and then do split/splice, pushing one half of data, then split again etc until I find the word to replace. But again, that does seem overkill for what could be a pretty basic problem
3
Answers
Try code below.
output is
Key point to note is that nested hashes in perl use references, which are akin to pointers in C/C++ land. Means that after running this line
both the
ad_1
andad_101
keys reference the same data, namely[EDIT – answering some of the comments]
I changed the
data
values to highlight that the reference inad_1
andad_101
are pointing to unique data in the JSON document. You didn’t supply any data, so I made some up.Use of
from_json
andto_json
rather thandecode_json
&encode_json
is purely to allow thepretty
parameter to be controlled. Use the variant that suits your use-case. Check out the docs hereAnother option is to use jq, rather than Perl
Assuming
data.json
contains thisthis one-liner to do the rename
output is
to get
jq
to output as a single line, add the-c
option to the commandlineThe others have answered this question adequately, and I’d also choose jq (see Using jq how can I replace the name of a key with something else and the jq FAQ).
But, I want to emphasis what @pmqs is doing but not yelling from the rooftops.
It’s just Perl
If you want to do something in Perl, you basically have scalars, arrays, and hashes. If you are already in Perl land, that’s what you are manipulating.
You don’t change a JSON key in Perl; you change a hash key. It doesn’t matter that you got that hash from JSON or will output it as JSON. That’s how you get to @pmqs’s
delete
:Everything beyond that is just input and output.
The right tool for the right job
You have a few other questions about the output, and those questions are unrelated to changing a hash key. When I deal with this, I simply ignore it. If it outputs it all on one line, I don’t really care. I can get pretty output with
jq
:If I want to minify it, I can use
testing
:You mentioned that you didn’t like the indention. That’s easy to change.
jq
uses 2 space indents, but I can make that smaller (or larger, or tabs) (see also How to restrict indentation while using jq filters on json file):You say that you can’t use
jq
because you are using Perl, but remember, Perl is the glue language of the internet. You can easily call other programs to do your work and you are expected to do so when something else can do the job better. Why wrestle with Perl and its modules when an existing tool already does a better job? If you aren’t able to install it for whatever reason, that’s fine. But saying that you can only choose one tool unnecessarily limits you.Setting aside that, JSON::PP has settings for
space_before
,space_after
,indent
, andindent_length
. You can adjust those how you like. If you have problems with those, you can ask a separate question.