使用Data :: Dump与JSON :: XS结合使用的奇怪行为

时间:2014-07-22 05:46:49

标签: json perl

我正在尝试使用JSON::XS将数据从Perl哈希导出到Python字典。我想将数字导出为数字(而不是unicode文本)。但似乎在一个案例中很难实现:

use Data::Dump qw(dump);
use JSON::XS;
my $h={a=> 1};
dump($h);
my $js = encode_json $h;
print "$js\n";

这将数字1作为字符串输出:(输出为)

{ a => 1 }
{"a":"1"}

但仅限于我使用Data:Dump::dump。如果我删除了行dump($h),则会给出

{"a":1}

我期望(和需要)的输出。

我在Ubuntu 12.04上使用Perl版本5.14和5.16对此进行了测试。

2 个答案:

答案 0 :(得分:2)

Perl标量可以是多种内容,并根据它们的使用方式在各种事物之间自动转换。您可以使用Devel::Peek查看您正在处理的内容。这是一个例子。

use strict;
use warnings;

use Devel::Peek ();

my $h = { foo => 42 };

Devel::Peek::Dump( $h );

<强>输出

SV = IV(0x7fd5520291e8) at 0x7fd5520291f8
  REFCNT = 1
  FLAGS = (PADMY,ROK)
  RV = 0x7fd552003438
  SV = PVHV(0x7fd552008d20) at 0x7fd552003438
    REFCNT = 1
    FLAGS = (SHAREKEYS)
    ARRAY = 0x7fd551e003f0  (0:7, 1:1)
    hash quality = 100.0%
    KEYS = 1
    FILL = 1
    MAX = 7
    Elt "foo" HASH = 0xa8c24522
    SV = IV(0x7fd5520289f0) at 0x7fd552028a00
      REFCNT = 1
      FLAGS = (IOK,pIOK)
      IV = 42

这是关于我们的匿名哈希的一大堆内部信息,但重要的一点是在最后一行,这是一组描述哈希元素foo的东西。它显示IV = 42,表示此标量(与foo关联的哈希值)是 I nteger V alue。

如果我们首先通过Data::Dump运行会发生什么?

use strict;
use warnings;

use Devel::Peek ();
use Data::Dump ();

my $h = { foo => 42 };

Data::Dump::dump( $h );
Devel::Peek::Dump( $h );

<强>输出

SV = IV(0x7fce39829230) at 0x7fce39829240
  REFCNT = 1
  FLAGS = (PADMY,ROK)
  RV = 0x7fce39803438
  SV = PVHV(0x7fce39808d20) at 0x7fce39803438
    REFCNT = 1
    FLAGS = (OOK,SHAREKEYS)
    AUX_FLAGS = 0
    ARRAY = 0x7fce3940a340  (0:7, 1:1)
    hash quality = 100.0%
    KEYS = 1
    FILL = 1 (cached = 0)
    MAX = 7
    RITER = -1
    EITER = 0x0
    RAND = 0x3bebb965
    Elt "foo" HASH = 0x525af8b0
    SV = PVIV(0x7fce3982b238) at 0x7fce39828a00
      REFCNT = 1
      FLAGS = (IOK,POK,pIOK,pPOK)
      IV = 42
      PV = 0x7fce39430e20 "42"\0
      CUR = 2
      LEN = 16

通过Data::Dump运行,我们的哈希变化了很多。特别地,散列值42现在具有称为PV的字段,其是字符串"42"。那是因为当你有一个包含数字的标量,并且你在期望字符串的上下文中使用它时,Perl会默默地将它转换为字符串类型。 (实际上,这是一个偶数的specialer类型,它同时包含一个字符串一个数字。如果你真的想让人们出来,你甚至可以让它们成为different things。)

所以Data::Dump已经导致你的数字被字符串化了,JSON::XS看起来很糟糕,看看每个标量是什么样的,将它解释为字符串。

所以有几个选择。

选择第一个

在使用Data::Dump之前获取您的JSON字符串。这可能是最简单的。

选择第二个

在序列化为JSON之前为每个数值添加零,这会强制它们进入数字上下文。

use strict;
use warnings;
use 5.010;

use JSON::XS;

my %h;
$h{a} = "42";
say encode_json( \%h );
$h{a} += 0;
say encode_json( \%h );

<强>输出

{"a":"42"}
{"a":42}

有关JSON :: XS如何处理序列化启发式的更多信息,请参阅文档:

答案 1 :(得分:1)

似乎问题已在Data::Dump

的CPAN错误列表中得到解决

Bug #86592 for Data-Dump: undesirable change of SV flags

问题是source中的以下行:

    elsif (do {no warnings 'numeric'; $$rval + 0 eq $$rval}) {

更改整数的标志,使JSON :: XS认为它是一个字符串。

(模块何时会修复bug修复?有人知道吗?)