从perl中的hash ref动态创建url

时间:2013-11-16 18:38:36

标签: perl url hash nested-loops

我想从输入散列引用创建url。假设我给哈希引用

my $input_hash_ref = {
        '1' => 'A',
        '2' => 'B',
        '3' => {
                '4' => {
                        '5' => {
                                '6' => [
                                        'ice cream','drink'
                                        ],
                                '7' => 'large'
                        }
                 '8' => 'perl'
                 '9' =>  'rosy'
                },
          '10'=>'june'
        },


};

然后将其转换为

1=A&2=B&3.4.5.6=ice cream|drinks&3.4.5.7=large&3.8=perl&3.9=rosy&10=june

需要帮助。

3 个答案:

答案 0 :(得分:3)

我只是要说,你不应该使用join编写带有简单实现的查询字符串。

use URI;
use URI::QueryParam;
my $u = URI->new("","http");

然后你可以简单地说:

$u->query_param_append("1" => "A", "2" => "B", ....);

甚至

$u->query_form_hash( %somedata );

请注意,这不会自动处理序列化嵌套的自定义架构,但它确实会保证您将发出任何服务器都能理解的有效查询字符串。

虽然您也可以使用Perl模块从深度嵌套的Hash转换为Flat哈希并再次返回:

您可以使用它来转换双方格式。

使用示例:

use strict;
use warnings;
use utf8;

use Data::SplitSerializer;
use Data::Dump qw(pp);
use URI;
use URI::QueryParam;

my $input_hash = {
        '1' => 'A',
        '2' => 'B',
        '3' => {
                '4' => {
                        '5' => {
                                '6' => [
                                        'ice cream','drink'
                                        ],
                                '7' => 'large'
                        }
                },
        },
        '8' => 'june',
        '9' => "Challenging & Value",
};

my $flattened = Data::SplitSerializer->new( path_style => 'DZIL' )->serialize($input_hash);
pp $flattened;

my $uri = URI->new("http://example.com/thing?");
$uri->query_form_hash( $flattened );

printf "%s\n", $uri;

my $copy = URI->new( $uri . "" ); # simulate getting it server side
my $copy_hash = $copy->query_form_hash;
pp $copy_hash;

my $deep = Data::

SplitSerializer->new( path_style => 'DZIL' )->deserialize($copy_hash);
pp $deep;

示例输出:

{
  "1" => "A",
  "2" => "B",
  "3.4.5.6[0]" => "ice cream",
  "3.4.5.6[1]" => "drink",
  "3.4.5.7" => "large",
  "8" => "june",
  "9" => "Challenging & Value",
}
http://example.com/thing?9=Challenging+%26+Value&3.4.5.6%5B1%5D=drink&2=B&8=june&3.4.5.6%5B0%5D=ice+cream&1=A&3.4.5.7=large
{
  "1" => "A",
  "2" => "B",
  "3.4.5.6[0]" => "ice cream",
  "3.4.5.6[1]" => "drink",
  "3.4.5.7" => "large",
  "8" => "june",
  "9" => "Challenging & Value",
}
{
  1 => "A",
  2 => "B",
  3 => { 4 => { 5 => { 6 => ["ice cream", "drink"], 7 => "large" } } },
  8 => "june",
  9 => "Challenging & Value",
}

答案 1 :(得分:1)

use URI::Escape;
sub serial {
  my ($h, $p) = @_;

  return join "&", map {
    my $v = $h->{$_};
    my $ref = ref($v);
    my $isH = $ref eq "HASH";
    my $pp = join ".", grep defined, $p, $_;

    $v = $isH ? serial($v,$pp)
       : $ref ? join("|", map uri_escape($_), @$v)
       : uri_escape($v);

    $isH ? $v : "$pp=$v";
  }
  sort keys %$h;
}

my $input_hash_ref = {
        '1' => 'A',
        '2' => 'B',
        '3' => {
                        '4' => {
                                '5' => {
                                        '6' => [
                                                'ice cream','drink'
                                                ],
                                          '7' => 'large'
                                          }
                                     },
                  },
        '8' => 'june'
};
print serial($input_hash_ref);

输出

1=A&2=B&3.4.5.6=ice cream|drink&3.4.5.7=large&8=june

答案 2 :(得分:0)

sub c {
    my ($v, $p) = @_;
    my $r = ref($v);
    return map { c($v->{$_}, $p ? $p . '.' . $_ : $_) } keys(%$v) if $r eq 'HASH';
    return $p . '=' . join('|', @$v) if $r eq 'ARRAY';
    return $p . '=' . $v;
}

say(join('&', c($input_hash_ref)));