2014-11-08 73 views
3

我想JSON:XS在一行上输出数组元素。例如:格式阵列的JSON输出

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; 

这给出输出:

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

而我的期望的输出是:

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

回答

2

此行为在模块中硬编码。如果您没有问题修补您电脑上的模块代码就可以轻松完成(以下说明是针对Linux的CPAN):

  1. 转至CPAN build目录/root/.cpan/build/JSON-XS-3.01-*(实际名称具有在年底一些随机字符)
  2. 应用下面的补丁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, ']'); 
  • 运行make,然后make install

  • 检查你的脚本:

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

    一些必要的声明:接受你自己的风险局部地改变模块,当然正确的做法是有一个良好的补丁,它会接受相应的配置选项,并将该补丁提交给模块的作者。但是,如果您只需要在计算机上运行它,那就完美了。

    +0

    谢谢!这看起来不错,但我找不到'XS.xs'文件。其他人(在其他机器上)也会使用这个程序,所以我认为这不是一个在本地修改源代码的选项。最好是提交给我认为模块作者的补丁。不管怎么说,还是要谢谢你! – 2014-11-08 12:03:18

    +0

    您是从CPAN手动安装软件包还是使用软件包管理器?如果你是从软件包安装的,删除它('rpm -e perl-JSON-XS'或类似的东西,取决于你的系统),然后用CPAN安装:'perl -MCPAN -e'install JSON :: XS'' 。您将拥有一个带有模块源代码的“build”目录,包括'XS.xs'。 – afenster 2014-11-08 12:06:06

    +0

    或者用这个补丁重建RPM也许更好。取决于你喜欢哪种方法。 – afenster 2014-11-08 12:06:31

    0

    如果阵列不能包含哈希,以下可能是解决方法:

    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); 
    } 
    

    输出:

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