1

I want to create url from input hash ref. Suppose I give hash ref as

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


};

Then this is to be converted as

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

Help needed.

1
  • 2
    Where did perl and rosy come from? Commented Nov 16, 2013 at 19:09

3 Answers 3

3

I just have to say, you shouldn't be composing query strings with a naive implementation with join.

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

Then you can simply:

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

Or even

$u->query_form_hash( %somedata );

Note that this does not automatically deal with your custom schema for serialized nesting, but it does guarantee that you'll emit a valid query string that any server will understand.

Though you can also use a Perl Module to convert from a deeply-nested Hash to a Flat hash and back again:

And you can use this to convert between formats on both sides.

Example usage:

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;

Example Output:

{
  "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",
}
Sign up to request clarification or add additional context in comments.

Comments

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

output

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

1 Comment

The reason you shouldn't DIY: my $input_hash_ref = { "1" => "Hello & Goodbye" }; # Will emit a broken query string.
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)));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.