JSON array output format

I would like to JSON:XS

output the elements of an array on one 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 the result:

{
   "b" : 3,
   "a" : [
      1,
      2,
      3,
      4
   ]
}

      

whereas my desired result is:

{
   "b" : 3,
   "a" : [ 1, 2, 3, 4 ]
}

      

+3


source to share


2 answers


This behavior is hardcoded into the module. If you are ok with fixing the module code on your computer, it can be easily done (the following instructions are for Linux CPAN):

  • Go to your CPAN build directory /root/.cpan/build/JSON-XS-3.01-*

    (the actual name has some random characters at the end)
  • Apply the following patch to 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, ']');

      



  1. Run make

    , then make install

    .

  2. Check your script:

$ perl json.pl
{
   "a" : [1, 2, 3, 4],
   "b" : 3
}

      

Some obligatory disclaimer: agree to modify the module locally at your own risk, in the correct way, to make a good patch that agrees with the corresponding configuration option, and send that patch to the author of the module. But if you only need it to work on your computer, that works great.

+2


source


If the arrays cannot contain hashes, there can be a 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 ]
}

      

0


source







All Articles