Thanks! By using Tie::Hash::MultiValueOrdered to create the initial hash, and then JSON::MultiValueOrdered to serialize it into JSON, the serialized output was in the right order.
use warnings;
use strict;
use autodie;
use JSON;
use Data::Dumper;
use 5.010;
my @order = qw/id disp ver auth/;
my $dat = [ ({ id => 'a', disp => 'a', ver => 'a', auth => 'a' })x2 ];
+ # dummy data
local $\ = "\n";
print 'Unsorted => ', JSON->new->indent->space_after->encode( $dat );
print 'Alpha Sorted => ', JSON->new->indent->space_after->canonical->e
+ncode( $dat );
print 'My Order => ', my $pryrtstr = manual_ordered_json( $dat, \@orde
+r );
{
# [tobyink][id://11111911]
use JSON::MultiValueOrdered;
use Tie::Hash::MultiValueOrdered;
my $tied = tie my %hash, 'Tie::Hash::MultiValueOrdered';
$hash{id} = 'a';
$hash{disp} = 'a';
$hash{ver} = 'a';
$hash{auth} = 'a';
#my $d2 = [ {%hash}, {%hash} ]; # didn't maintain order -- oh,
+ right, because that made a normal hashref from an ordered hash; duh!
my $d2 = [ \%hash, \%hash ]; # does maintain order
print 'tobyink => ', my $tobyinkstr = JSON::MultiValueOrdered->new
+(pretty=>1)->encode($d2);
use Test::More tests => 1;
$tobyinkstr =~ s/\s//g;
$pryrtstr =~ s/\s//g;
is_deeply $tobyinkstr, $pryrtstr, 'serialization match';
done_testing;
}
sub manual_ordered_json{
my @list = @{$_[0]};
my @ordr = @{$_[1]};
my $out = "[\n";
for my $i ( 0 .. $#list ) {
my $h = $list[$i];
$out .= " {\n";
for my $j ( 0 .. $#ordr ) {
my $k = $ordr[$j];
next unless defined $k;
next unless exists $h->{$k};
$out .= sprintf qq| "%s": "%s"|, $k, $h->{$k} // '<
+undef>';
$out .= ',' if $j < $#ordr;
$out .= "\n";
}
$out .= " }";
$out .= "," if $i < $#list;
$out .= "\n";
}
$out .= "]\n";
return $out;
}
(As you can tell from my commented-out line, I had a brain failure in my first attempt, and converted the ordered hash into a plain hashref, thus losing the original order. Once I realized that, I got it working.)