【问题标题】:How can I parse complex query strings generated by jQuery.ajax() in Perl?如何在 Perl 中解析由 jQuery.ajax() 生成的复杂查询字符串?
【发布时间】:2017-03-01 17:47:27
【问题描述】:

jQuery.ajax() 将复杂的 JavaScript 对象编码成这样的查询字符串:

?a[b][]=1&a[b][]=2&a[c]=3

我想把它解码成这样的 Perl 数据结构:

{ a=>{ b=>[1,2], c=>3 } }

PHP 默认执行此操作。有没有办法在 Perl CGI 脚本中也能做到这一点?不一定使用 CGI.pm;我可以安装任何我想要的库。

目前我只能解码一维数组,因为 CGI 模块的param() 函数可以返回一个数组。

【问题讨论】:

  • @choroba 这不是 JSON。
  • 我知道但不能改用 JSON 吗?
  • 你控制 JavaScript 代码吗?如果是这样,请将您的对象转换为 JSON 字符串,对其进行 URL 编码,然后发送。 JSON 是独立于语言的标准,而 jQuery 的 .param 方法则不是。另见stackoverflow.com/q/15872658
  • @ThisSuitIsBlackNot 更好的是,跳过所有 URI 编码、查询解析、查询参数大小限制以及通过 GET 和 POST JSON 发送数据的安全问题。

标签: perl parsing cgi query-string


【解决方案1】:

您是否考虑过以 JSON 格式提交数据?简直就是更换的问题

data: data

data: JSON.stringify(data)

您甚至可以切换到 POST 以避免 URI 编码、URI 解码和查询大小限制(尽管 POST 语义不同于 GET 语义)。

method:      "POST",
contentType: "application/json; charset=UTF-8",
data:        JSON.stringify(data)

无论如何,以下应该可以解决问题:

use Data::Diver qw( DiveVal );
use List::Util  qw( pairs );  # 1.29+
use URI         qw( );

my $url = URI->new('?a[b][]=1&a[b][]=2&a[c]=3', 'http');

my %data;
PAIR: for ( pairs( $url->query_form() ) ) {
   my ($k, $v) = @$_;

   my ( @k, $push );
   for (my $k_ = $k) {  # Basically C<< my $_ = $k; >>
      s/^(\w+)//
         or warn("Can't handle key $k\n"), next PAIR;

      push @k, $1;
      push @k, $1 while s/^\[(\w+)\]//;
      $push = s/^\[\]//;

      $_ eq ""
         or warn("Can't handle key $k\n"), next PAIR;
   }

   if ($push) {
      push @{ DiveVal(\%data, @k) }, $v;
   } else {
      DiveVal(\%data, @k) = $v;
   }
}

5.16 之前的 Perl 版本需要解决方法。替换

use Data::Diver qw( DiveVal );
push @{ DiveVal(\%data, @k) }, $v;

use Data::Diver qw( DiveRef DiveVal );
push @{ ${ DiveRef(\%data, @k) } }, $v;

请注意,格式不明确[1]。例如,以下两个表达式产生相同的结果(a[0][x]=3[2]):

jQuery.param( { a: [      { x: 3 } ] } )

jQuery.param( { a: { "0": { x: 3 } } } )

我的代码将重现前者。数字键始终被视为数组索引。


  1. 使用 JSON 的另一个原因。
  2. 为了便于阅读,删除了一些转义。

【讨论】:

  • 考虑把它变成一个模块?
  • 没有规范,但implementation 很短。当然,这些年来它已经改变了好几次......
  • @ikegami 我试过你的功能,但它说:Can't use an undefined value as an ARRAY reference at test.pl line 25. 这是行:push @{ DiveVal(\%data, @k) }, $v; 我不能说我明白你在做什么所以你能帮我纠正它吗?
  • @ikegamy 也不应该for (my $k_ = $k) 是:for (my $_ = $k) 我认为这只是一个错字。
  • 如果可以使用my $_ = $k;,则根本不需要forfor (my $k_ = $k) { ... } 用作my $_ = $k; ... 的替代品,这意味着它创建了一个词法范围的$_,它是$k 的副本。
【解决方案2】:

PHP 对foo[]=123&amp;foo[]=234&amp;foo[]=345 之类的查询字符串的解释不同于所有 Perl Web 框架。我曾经为 Mojolicious 构建了一个 PHP 插件,并且不得不解决很多这些差异。您可以找到这些差异的摘要和一些工作代码(无论如何,最多可用于 2 级哈希)以将 Perl 参数转换为 PHP 样式的参数 here。也许您可以根据您的用例对其进行调整。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-17
    • 2016-06-20
    • 1970-01-01
    相关资源
    最近更新 更多