Re^2: Preserve the order in JSON
by choroba (Cardinal) on Jul 11, 2018 at 10:57 UTC
|
If you need to preserve the order, don't use "JSON object" (aka hash in Perl) as the data structure, use an array (or include an ordering attribute to the object).
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] |
Re^2: Preserve the order in JSON
by Deven (Novice) on Sep 11, 2023 at 07:11 UTC
|
Every time someone says they want to preserve the order of JSON keys, people jump on them for it, saying the keys are unordered by definition and why should they want that anyway? There are use cases for this!! Take the example of a JSON configuration file that happens to be stored in a git repository. Suppose you want to modify the JSON programmatically to make a slight change. If the keys are kept in the original order, a "git diff" of the changes will show a tiny change clearly. If all the hash keys are in a new randomized order, the diff will be mostly noise and the change will be very difficult to find.
Anyway, I came up with a good solution for this using Monkey::Patch with JSON::PP to make it use Tie::IxHash for all objects decoded from JSON. This solves the problem, allowing a JSON file to be loaded, decoded from JSON, modified, encoded into JSON again and written back to the file, without changing the key ordering at all. Just make sure you're using JSON::PP (not JSON::XS) and that the $handle variable remains in scope:
use Monkey::Patch qw[patch_package];
# Monkey-patch JSON::PP::object() subroutine to use Tie::IxHash.
my $handle = patch_package 'JSON::PP' => 'object' => sub {
my $orig = shift;
my %obj;
tie %obj, 'Tie::IxHash'
or die "tie(\%obj, 'Tie::IxHash') failed!\n";
$orig->(\%obj)
};
| [reply] [d/l] [select] |
|
| [reply] [d/l] |
|
{
"foo": 1,
"bar": 2,
"foo": 3
}
If you parse the above into $data then $data->{foo} will be 3, but tied(%$data)->get('foo') in list context will return ( 1, 3 ), and if you serialize the structure, you'll get this, preserving the original order of the keys:
{
"foo": 1,
"bar": 2,
"foo": 3
}
| [reply] [d/l] [select] |
|
> saying the keys are unordered by definition and why should they want that anyway
AFAIR is this disputed, because different RFC tell differently.
JS Objects are unsorted tho and JSON stands for "JS Object Notation".
The curlies in JS { ... } create literal objects (kind of hashes plus inheritance chain).
Different definitions will lead to much confusion...
| [reply] [d/l] |
|
| [reply] |
Re^2: Preserve the order in JSON
by Anonymous Monk on Oct 21, 2020 at 03:48 UTC
|
I have a reason why. I have a vim command that I use that Tidies different files.
:Tidy
When it's perl code, it uses the Perl::Tidy. If it's JSON, then it formats it nicely using JSON::PP. Recently I've been doing comparisons of serialized JSON data (to make sure it's formatted correctly) and it would be nice if the order was maintained when being Tidied.
Performance isn't critical, it's an editor command; not used in production.
| [reply] [d/l] |
|
I've been using a one-liner.
json_pp -f json -t json -json_opt pretty. I may end up implementing it using Hash::Ordered
| [reply] [d/l] |
|
| [reply] |
|
Use the ordering/sorting feature then nobody is stopping you
| [reply] |