Perl、JSON、浮点数、引号

Perl, JSON, float, quotes

我们有一个 Perl 应用程序,它根据数据库查询创建 JSONs。不幸的是,它错误地处理了浮点数,因为它在浮点数周围加上了双引号。

例如:

use DBI;
use JSON::MaybeXS;

my $dbs="dbi:ODBC:myconnection,myuser,mypwd,";
my @ARR=split/,/ ,$dbs;
$dbh = DBI->connect(@ARR, { PrintError=>0, RaiseError=>1,  LongReadLen=>60000}) ;
my $sql = "SELECT 'Hello there' str, '0.0123' str_flt, 0.0123 flt_sm, 10.1234 flt_lg, 1234 nt, getdate() dt";
my $sth = $dbh->prepare($sql);
$sth->execute();

my $rows = $sth->fetchall_arrayref({});

print "Structure of result is: \n\n";
my $num_fields = $sth->{NUM_OF_FIELDS};
for ( my $i=0; $i< $num_fields; $i++ ) {
    my $field = $sth->{NAME}->[$i];
    my $type = $sth->{TYPE}->[$i];
    my $precision = $sth->{PRECISION}->[$i]; # e.g. VARCHAR(50) has a precision of 50
    print "Field $field is of type $type, with precision $ precision\n";
}

$sth->finish();
$dbh->disconnect;

my $json_opts = JSON::MaybeXS->new(utf8 => 1, pretty => 1);
my $json_maybe = $json_opts->encode($rows);

print("\nJSON::MaybeXS:\n");
print($json_maybe);

输出如下:

Structure of result is:

Field str is of type -8, with precision 11
Field str_flt is of type -8, with precision 6
Field flt_sm is of type 2, with precision 4
Field flt_lg is of type 2, with precision 6
Field nt is of type 4, with precision 10
Field dt is of type 93, with precision 23

JSON::MaybeXS:
[
   {
      "dt" : "2018-10-05 09:42:43.483",
      "nt" : 1234,
      "flt_sm" : ".0123",
      "str" : "Hello there",
      "str_flt" : "0.0123",
      "flt_lg" : "10.1234"
   }
]

Perl 版本:5.18.2

已安装 JSON 库:JSON、JSON-Any、JSON-PP、JSON-XS、Cpanel-JSON -XS,JSON-MaybeXS,Parse-CPAN-Meta

有一件事,输出打乱了字段,每个 运行 导致 JSON 中的顺序不同。主要问题是浮点数周围的双引号,这会导致在另一个应用程序中使用它时出现问题,因为它将这些字段识别为字符串并且必须一个一个地解析它们。 DBI 正确识别字段类型,它在 json 编码期间以某种方式丢失了......知道如何解决它吗? (是的,我可以使用正则表达式轻松修复它,但那不是很好...)

这就是 Cpanel::JSON::XS has Cpanel::JSON::XS::Type 的原因。请注意,浮点数可能会丢失精度。

#!/usr/bin/perl
use warnings;
use strict;

use Cpanel::JSON::XS;
use Cpanel::JSON::XS::Type;

my $type = json_type_arrayof({
    dt      => JSON_TYPE_STRING,
    nt      => JSON_TYPE_INT,
    flt_sm  => JSON_TYPE_FLOAT,
    str     => JSON_TYPE_STRING,
    str_flt => JSON_TYPE_FLOAT,
    flt_lg  => JSON_TYPE_FLOAT,
});


my $data = [{
    dt      => "2018-10-05 09:42:43.483",
    nt      => 1234,
    flt_sm  => ".0123",
    str     => "Hello there",
    str_flt => "0.0123",
    flt_lg  => "10.1234",
}];

my $jsonizer = Cpanel::JSON::XS->new->canonical->pretty;
print $jsonizer->encode($data, $type);

尝试这样的操作,通过添加 0 将您的数字字段转换为数字。类似的方法对我有用过一次。使用 JSON::XS 版本 3.02.

use JSON::XS 3.02;
...
my @numfield=qw( nt flt_sm str_flt flt_lg );
for my $f (@numfield) {
  defined $$_{$f} and $$_{$f}+=0 for @$rows;
}
...