groups of inputs using CGI.pm

Discussion in 'Perl Misc' started by Paul Lalli, Aug 25, 2005.

  1. Paul Lalli

    Paul Lalli Guest

    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)
     
    Paul Lalli, Aug 25, 2005
    #1
    1. Advertising

  2. Paul Lalli

    Paul Lalli Guest

    Paul Lalli wrote:
    > 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
     
    Paul Lalli, Aug 25, 2005
    #2
    1. Advertising

  3. Paul Lalli

    Brian Wakem Guest

    Paul Lalli wrote:

    > 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.


    --
    Brian Wakem
    Email: http://homepage.ntlworld.com/b.wakem/myemail.png
     
    Brian Wakem, Aug 25, 2005
    #3
  4. Paul Lalli

    Guest

    Paul Lalli wrote:
    > 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


    --
    Hope this helps,
    Steven
     
    , Aug 25, 2005
    #4
  5. Paul Lalli

    Guest

    "Paul Lalli" <> wrote:
    ....
    > 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

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Aug 25, 2005
    #5
  6. Paul Lalli

    Paul Lalli Guest

    wrote:
    > "Paul Lalli" <> wrote:
    > ...
    > > 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/;


    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
     
    Paul Lalli, Aug 26, 2005
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    24
    Views:
    992
    Mike Treseler
    Jul 29, 2005
  2. Petra Hübner
    Replies:
    0
    Views:
    446
    Petra Hübner
    Feb 16, 2004
  3. anonymous
    Replies:
    1
    Views:
    4,595
    Francisco Padron
    May 8, 2005
  4. Replies:
    3
    Views:
    363
    Peter Hansen
    Jun 10, 2005
  5. Replies:
    15
    Views:
    727
    Alan J. Flavell
    Dec 30, 2004
Loading...

Share This Page