Reputation: 40718
I would like JSON:XS
to output array elements on a single line. For example:
use warnings;
use strict;
use JSON::XS;
my $h={a=>[1,2,3,4],b=>3};
my $coder = JSON::XS->new->pretty;
my $txt = $coder->encode($h);
print $txt;
This gives output:
{
"b" : 3,
"a" : [
1,
2,
3,
4
]
}
whereas my desired output is:
{
"b" : 3,
"a" : [ 1, 2, 3, 4 ]
}
Upvotes: 3
Views: 267
Reputation: 3608
This behavior is hardcoded in the module. If you are ok with patching the module code on your computer it can be easily done (the following instructions are for Linux CPAN):
/root/.cpan/build/JSON-XS-3.01-*
(the actual name has some random characters at the end)XS.xs
:--- XS.xs.orig 2014-11-08 14:22:37.682348401 +0300
+++ XS.xs 2014-11-08 14:30:01.447643990 +0300
@@ -486,6 +486,15 @@
encode_space (enc);
}
+INLINE void
+encode_comma_singleline (enc_t *enc)
+{
+ encode_ch (enc, ',');
+
+ if (enc->json.flags & F_SPACE_AFTER)
+ encode_space (enc);
+}
+
static void encode_sv (enc_t *enc, SV *sv);
static void
@@ -500,24 +509,18 @@
if (len >= 0)
{
- encode_nl (enc); ++enc->indent;
-
for (i = 0; i <= len; ++i)
{
SV **svp = av_fetch (av, i, 0);
- encode_indent (enc);
-
if (svp)
encode_sv (enc, *svp);
else
encode_str (enc, "null", 4, 0);
if (i < len)
- encode_comma (enc);
+ encode_comma_singleline (enc);
}
-
- encode_nl (enc); --enc->indent; encode_indent (enc);
}
encode_ch (enc, ']');
Run make
, then make install
.
Check your script:
$ perl json.pl
{
"a" : [1, 2, 3, 4],
"b" : 3
}
Some required disclaimer: accept changing the module locally at your own risk, the correct way of course is to make a good patch which would accept the corresponding configuration option, and submit this patch to the author of the module. But if you need it to run on your computer only, that will perfectly work.
Upvotes: 2
Reputation: 40718
If arrays cannot contain hashes, the following could be workaround:
use warnings;
use strict;
use JSON::XS;
use Text::Balanced qw(extract_bracketed extract_delimited);
use Text::CSV;
my $csv = Text::CSV->new( { sep_char => ',', allow_whitespace => 1 } );
my $h = { a => "[", g => [ "[", 2, "bb]]", 4 ], b => 3, c => [ 1, 2, 3, 4 ] };
my $coder = JSON::XS->new->pretty;
my $txt = $coder->encode($h);
my $str = "";
while (1) {
my $ind1 = index( $txt, '"' );
my $ind2 = index( $txt, '[' );
if ( $ind1 >= 0 && $ind2 >= 0 ) {
if ( $ind1 < $ind2 ) {
skipQuoted( \$txt, \$str );
next;
}
}
elsif ( $ind2 < 0 ) {
$str .= $txt;
last;
}
my ( $etxt, $end, $beg ) = extract_bracketed( $txt, '["]', '[^[]*' );
die "Unexpected!" if !defined $etxt;
$str .= $beg;
$etxt = substr( $etxt, 1, length($etxt) - 2 )
; #strip leading and trailing brackets
$etxt =~ s{\n}{}g;
my @elem;
if ( $csv->parse($etxt) ) {
@elem = $csv->fields();
}
else {
die "Unexpected!";
}
$str .= '[ ' . processFields( \@elem ) . ' ]';
$txt = $end;
}
print $str;
sub skipQuoted {
my ( $txt, $str ) = @_;
my ( $s1, $s2, $s3 ) = extract_delimited( $$txt, '"', '[^"]*' );
die "Unexpected!" if !defined $s1;
$$str .= $s3 . $s1;
$$txt = $s2;
}
sub processFields {
my ($a) = @_;
for (@$a) {
if ( $_ !~ /^-?(0|([1-9][0-9]*))(\.[0-9]+)?([eE][-+]?[0-9]+)?$/ ) {
$_ = '"' . $_ . '"';
}
}
return join( ", ", @$a );
}
Output:
{
"a" : "[",
"g" : [ "[", 2, "bb]]", 4 ],
"b" : 3,
"c" : [ 1, 2, 3, 4 ]
}
Upvotes: 0