groups of inputs using CGI.pm

P

Paul Lalli

Greetings. Using Perl and CGI.pm, can someone recommend a decent way
of
processing groups of inputs and parameters? As an example, say I have
a
form to record student grades:

<form method="post" action="grades.cgi">
John - <input type="radio" name="john_grade" value="A">
<input type="radio" name="john_grade" value="B">
<input type="radio" name="john_grade" value="C">
<input type="radio" name="john_grade" value="D">
<input type="radio" name="john_grade" value="F">
<input type="text" name="john_comments" value="">
<br />
Mary - <input type="radio" name="mary_grade" value="A">
<input type="radio" name="mary_grade" value="B">
<input type="radio" name="mary_grade" value="C">
<input type="radio" name="mary_grade" value="D">
<input type="radio" name="mary_grade" value="F">
<input type="text" name="mary_comments" value="">
<br />
<!-- etc -->
</form>

(This is for demonstration purposes - real code would use a unique
identifier, like student id, as the prefix).

As you can see, for large numbers of students, this would quickly
become
unweildy. I currently have only one thought as to how to process these

fields - retrieve a list of parameters, grep()'ing for the ones I want,
and
process the groups:

my @grades = grep { /_grade$/ } param();
for (@grades){
my $name = /^(\w+)_grade/;
print "$name has grade: ", param($_), "\n";
print "Comments: ", param($name.'_comments'), "\n\n";
}

That seems messy at best. This is especially annoying to me, because I
know
that in PHP, I can make my inputs look like this:
<input type="radio" name="grade[john]" value="A">
<input type="radio" name="grade[john]" value="B">
<input type="radio" name="grade[john]" value="C">
<input type="radio" name="grade[john]" value="D">
<input type="radio" name="grade[john]" value="F">
<input type="text" name="comments[john]" value="">
and then retrieve the list of names with:
$grades = $_POST['grades'];
foreach ($grades as $name => $grade) {
echo "$name has grade: $grade\n";
echo "Comments: $_POST[comments][$name]\n\n";
}

(syntax may not be correct - it's been a long while since I used
PHP...)

Is there any similar way I can work with CGI.pm's param() function to
retrieve a multi-dimensioned structure? Alternatively, can someone
suggest
a way of processing similarly-purposed fields like this? I strongly
doubt
that this is such a rare problem that someone hasn't already solved it.

I'm much more inclined to beileve that I'm either not thinking hard
enough
or not searching well enough.

Thanks for any assistance you can provide.

Paul Lalli

P.S. (I don't *think* this is a truly CGI problem, but if I would be
better off in the comp.web.authoring.cgi (or similar) group, please let
me know)
 
P

Paul Lalli

Paul said:
Greetings. Using Perl and CGI.pm, can someone recommend a decent way
of
processing groups of inputs and parameters? As an example, say I have
a
form to record student grades:

GAH! My profuse apologies for the messed up line-lengths. :-(

Paul Lalli
 
B

Brian Wakem

Paul said:
Greetings. Using Perl and CGI.pm, can someone recommend a decent way
of
processing groups of inputs and parameters? As an example, say I have
a
form to record student grades:

<form method="post" action="grades.cgi">
John - <input type="radio" name="john_grade" value="A">
<input type="radio" name="john_grade" value="B">
<input type="radio" name="john_grade" value="C">
<input type="radio" name="john_grade" value="D">
<input type="radio" name="john_grade" value="F">
<input type="text" name="john_comments" value="">
<br />
Mary - <input type="radio" name="mary_grade" value="A">
<input type="radio" name="mary_grade" value="B">
<input type="radio" name="mary_grade" value="C">
<input type="radio" name="mary_grade" value="D">
<input type="radio" name="mary_grade" value="F">
<input type="text" name="mary_comments" value="">
<br />
<!-- etc -->
</form>

(This is for demonstration purposes - real code would use a unique
identifier, like student id, as the prefix).

As you can see, for large numbers of students, this would quickly
become
unweildy. I currently have only one thought as to how to process these

fields - retrieve a list of parameters, grep()'ing for the ones I want,
and
process the groups:

my @grades = grep { /_grade$/ } param();
for (@grades){
my $name = /^(\w+)_grade/;
print "$name has grade: ", param($_), "\n";
print "Comments: ", param($name.'_comments'), "\n\n";
}

That seems messy at best. This is especially annoying to me, because I
know
that in PHP, I can make my inputs look like this:
<input type="radio" name="grade[john]" value="A">
<input type="radio" name="grade[john]" value="B">
<input type="radio" name="grade[john]" value="C">
<input type="radio" name="grade[john]" value="D">
<input type="radio" name="grade[john]" value="F">
<input type="text" name="comments[john]" value="">
and then retrieve the list of names with:
$grades = $_POST['grades'];
foreach ($grades as $name => $grade) {
echo "$name has grade: $grade\n";
echo "Comments: $_POST[comments][$name]\n\n";
}

(syntax may not be correct - it's been a long while since I used
PHP...)

Is there any similar way I can work with CGI.pm's param() function to
retrieve a multi-dimensioned structure? Alternatively, can someone
suggest
a way of processing similarly-purposed fields like this? I strongly
doubt
that this is such a rare problem that someone hasn't already solved it.

I'm much more inclined to beileve that I'm either not thinking hard
enough
or not searching well enough.

Thanks for any assistance you can provide.

Paul Lalli


I think I would use something like this:-

# untested
my $query = new CGI;
foreach my $student($query->param()) {
next if (index($student, '_grade') eq -1 );
$student =~ s!_grade$!!;
print "$student has grade: " . $query->param("${student}_grade") . "\n";
print "Comments: " . $query->param("${student}_comments") . "\n";
}

Or read into hash first:-

# untested
my $query = new CGI;
my %student;
foreach my $student($query->param()) {
next if (index($student, '_grade') eq -1 );
$student =~ s!_grade$!!;
$student{$student}{'grade'} = $query->param("${student}_grade");
$student{$student}{'comments'} = $query->param("${student}_comments")
}


Not sure there's too much advantage over your grep method, but I'd imagine
my way would be faster.
 
A

attn.steven.kuo

Paul said:
Greetings. Using Perl and CGI.pm, can someone recommend a decent way
of
processing groups of inputs and parameters? As an example, say I have
a
form to record student grades:

<form method="post" action="grades.cgi">
John - <input type="radio" name="john_grade" value="A">
<input type="radio" name="john_grade" value="B">
<input type="radio" name="john_grade" value="C">
<input type="radio" name="john_grade" value="D">
<input type="radio" name="john_grade" value="F">
<input type="text" name="john_comments" value="">
<br />
Mary - <input type="radio" name="mary_grade" value="A">
<input type="radio" name="mary_grade" value="B">
<input type="radio" name="mary_grade" value="C">
<input type="radio" name="mary_grade" value="D">
<input type="radio" name="mary_grade" value="F">
<input type="text" name="mary_comments" value="">
<br />
<!-- etc -->
</form>

(This is for demonstration purposes - real code would use a unique
identifier, like student id, as the prefix).

As you can see, for large numbers of students, this would quickly
become
unweildy.


(snipped comparison of Perl vs PHP code)
Is there any similar way I can work with CGI.pm's param() function to
retrieve a multi-dimensioned structure? Alternatively, can someone
suggest
a way of processing similarly-purposed fields like this? I strongly
doubt
that this is such a rare problem that someone hasn't already solved it.

I'm much more inclined to beileve that I'm either not thinking hard
enough
or not searching well enough.

Thanks for any assistance you can provide.

Paul Lalli

P.S. (I don't *think* this is a truly CGI problem, but if I would be
better off in the comp.web.authoring.cgi (or similar) group, please let
me know)


Perhaps using CGI::Vars() and transforming
the information into a multi-level hash? E.g.,

#!/usr/bin/perl
use strict;
use warnings;
use CGI qw:)standard :cgi-lib);

my %param = Vars();
my %post;

while (my ($k, $v) = each %param)
{
my ($item, $person) = $k =~ /(.*)_(.*)/;
next unless (length($item) and length($person));
$post{$item}{$person} = $v;
}

while (my ($person, $grade) = each %{ $post{'grade'} })
{
print "$person has grade $grade\n";
print "Comments: $post{comments}{$person}\n\n"
if exists $post{comments}{$person};
}



$ ./demo.pl grade_john=F grade_mary=A comments_john='My dog ate my
homework'
john has grade F
Comments: My dog ate my homework

mary has grade A
 
X

xhoster

Paul Lalli said:
I currently have only one thought as to how to process these

fields - retrieve a list of parameters, grep()'ing for the ones I want,
and
process the groups:

my @grades = grep { /_grade$/ } param();
for (@grades){
my $name = /^(\w+)_grade/;

I'm pretty sure this doesn't do what you think it does. You mean:
my ($name) = /^(\w+)_grade/;

print "$name has grade: ", param($_), "\n";
print "Comments: ", param($name.'_comments'), "\n\n";
}

That seems messy at best. This is especially annoying to me, because I
know
that in PHP ....

$grades = $_POST['grades'];
foreach ($grades as $name => $grade) {
echo "$name has grade: $grade\n";
echo "Comments: $_POST[comments][$name]\n\n";
}

(syntax may not be correct - it's been a long while since I used
PHP...)

These two chunks of code look remarkably similar to me. Since I don't know
what is annoying about the Perl code, I don't know what to advice in order
to fix it. What specifically do you find annoying about it?

Is there any similar way I can work with CGI.pm's param() function to
retrieve a multi-dimensioned structure? Alternatively, can someone
suggest
a way of processing similarly-purposed fields like this?

I'd do it somewhat the same way you did above, but I'd move the capturing
regex out of the loop. So I might go for this instead:

my @people = map /(.*)_grade$/, param();

Or, if you use a PHP style form, then

my @people = map /^grade\[(.*)]$/, param();

Or for a more general piece of code for doing python-like forms, not
specific to people's grades:

my %things; @things{ map /\[(.*)]$/, param() } = ();


You could probably subclass CGI and add a few methods that would do this in
a more php-like manner.


Xho
 
P

Paul Lalli

I'm pretty sure this doesn't do what you think it does. You mean:
my ($name) = /^(\w+)_grade/;

You are correct, of course. Thanks for catching that.
print "$name has grade: ", param($_), "\n";
print "Comments: ", param($name.'_comments'), "\n\n";
}

That seems messy at best. This is especially annoying to me, because I
know
that in PHP ...

$grades = $_POST['grades'];
foreach ($grades as $name => $grade) {
echo "$name has grade: $grade\n";
echo "Comments: $_POST[comments][$name]\n\n";
}

(syntax may not be correct - it's been a long while since I used
PHP...)

These two chunks of code look remarkably similar to me. Since I don't know
what is annoying about the Perl code, I don't know what to advice in order
to fix it. What specifically do you find annoying about it?

Basically the fact that I have to loop through the parameter list
looking for parameters that match the general pattern I'm looking for,
as opposed to having the structure already create for me ahead of time.
Is there any similar way I can work with CGI.pm's param() function to
retrieve a multi-dimensioned structure? Alternatively, can someone
suggest
a way of processing similarly-purposed fields like this?

I'd do it somewhat the same way you did above, but I'd move the capturing
regex out of the loop. So I might go for this instead:

my @people = map /(.*)_grade$/, param();

Or, if you use a PHP style form, then

my @people = map /^grade\[(.*)]$/, param();

Or for a more general piece of code for doing python-like forms, not
specific to people's grades:

my %things; @things{ map /\[(.*)]$/, param() } = ();


You could probably subclass CGI and add a few methods that would do this in
a more php-like manner.

Thanks for the tips.

Paul Lalli
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top