[Templates] Sticky forms with hierarchical template vars

Jason W. May jmay@pobox.com
Mon, 07 Jan 2002 23:27:45 -0800


Here's my contribution.  This one converts a HTTP query string to
a nested hash.  It tries to be a little smart about scalars vs. lists.

sub RollupParamString {
    my ($input) = @_;

    my $root = {};

    foreach my $nvp (split(/\n/, $input)) {
	last if $nvp eq "=";
	my ($name, $value) = split /=/, $nvp;

	my @levels = split /\./, $name;

	$value = CGI->unescape($value);

      TRAVERSE:
	my $node = $root;
	my $leaf;
	for ($leaf = shift @levels;
	     scalar(@levels) >= 1;
	     $leaf = shift @levels) {
	    $node->{$leaf} = {} unless defined $node->{$leaf};	# vivify
	      $node = $node->{$leaf};
	}

      SAVE:
	{
	    if (ref $node->{$leaf}) {
		# there's already a list there
		push @{$node->{$leaf}}, $value;
	    } elsif (defined $node->{$leaf}) {
		# scalar now, convert to a list
		$node->{$leaf} = [ $node->{$leaf}, $value ];
	    } else {
		$node->{$leaf} = $value;
	    }
	}
    }

    return $root;
}


Given this input:
name.first=Jane
name.last=Smith
address.street=123%20Main%20St.
address.city=New%20York
address.state=NY
phone=(212)123-4567
phone=(212)555-1212
id=4444

You get this output:
$VAR1 = {
          'address' => {
                         'state' => 'NY',
                         'city' => 'New York',
                         'street' => '123 Main St.'
                       },
          'id' => '4444',
          'phone' => [
                       '(212)123-4567',
                       '(212)555-1212'
                     ],
          'name' => {
                      'last' => 'Smith',
                      'first' => 'Jane'
                    }
        };