inblosam has asked for the wisdom of the Perl Monks concerning the following question:

In this node I got some advice on how to post and retrieve multiple rows of data. I am now getting an error using this: "Can't use string ("1") as an ARRAY ref while "strict refs" in use at...". I am using Mason, and one of the comments in the aforementioned node was trying to eliminate this problem, but I still get the same error (pointing to the "init" line).

The form being posted looks like this:
<input type="hidden" name="edit_item" value="1"> <input type="text" name="edit_name_1" value="hello" size="20">
The code that processes this looks as follows...
my @editlineitems = @{ $ARGS{ edit_item } }; foreach my $line (@editlineitems) { my $name = $ARGS{"edit_name_$line"}; }
Any help would be appreciated!


Michael Jensen

Replies are listed 'Best First'.
Re: can't use string as an array ref....
by monarch (Priest) on Jul 13, 2005 at 00:30 UTC
    It is possible, even highly likely, that $ARGS{edit_item} is a scalar containing the string "1".

    The complaint would be that you are attempting to dereference an array by sticking @{...} around the scalar item.

    You can confirm whether this is the case by commenting out the (potentially) offending code, and replacing it with:

    { use Data::Dumper; $m->out( '<pre>' . Dumper( \%ARGS ) . '</pre>' ); }
Re: can't use string as an array ref....
by monarch (Priest) on Jul 13, 2005 at 00:35 UTC
    So, after looking at your code, I'm guessing what you want is to process a form that looks something like
    <input type="text" name="edit_name_1" value="hello" size="20"> <input type="text" name="edit_name_2" value="world" size="20"> <input type="text" name="edit_name_3" value="form" size="20">
    ..where you have a number of edit_name_n fields.

    I suggest you do the following:

    foreach my $key ( keys %ARGS ) { # skip any arguments that aren't of interest next if ( $key !~ m/^edit_name_(\d+)$/ ); my $num = $1; # captured from the regexp my $name = $ARGS{$key}; $m->out( "<p>Edit field $num = $name</p>" ); }
      monarch has a nice, clean and safe proposal.

      The only thing I'd suggest is a sort befor keys, so that you get the edits in order.

           "Income tax returns are the most imaginative fiction being written today." -- Herman Wouk

      That works really great, thank you! I have more than one field (I simplified it for the sake of easy duplication), so besides edit_name_N I may have edit_type_N, what is the best way to work that in too? Another "next if" won't work, and when I just do an if it gives me everything posted.

      Thanks a ton! I like this way better than the other way from the other node I think.


      Michael Jensen
        There are numerous ways of approaching this. Two suggestions are:
        foreach my $key ( keys %ARGS ) { if ( $key =~ m/^edit_name_(\d+)$/ ) { my $num = $1; # captured from the regexp my $name = $ARGS{$key}; $m->out( "<p>Edit name $num = $name</p>" ); } elsif ( $key =~ m/^edit_type_(\d+)$/ ) { my $num = $1; # captured from the regexp my $type = $ARGS{$key}; $m->out( "<p>Edit type $num = $type</p>" ); } }

        The second method is to generate hashes to play with:

        my %edit_name = (); my %edit_type = (); foreach my $key ( keys %ARGS ) { if ( $key =~ m/^edit_name_(\d+)$/ ) { $edit_name{$1} = $ARGS{$key}; } elsif ( $key =~ m/^edit_type_(\d+)$/ ) { $edit_type{$1} = $ARGS{$key}; } } # play with values foreach my $num ( sort { $a <=> $b } keys %edit_name ) { $m->out( "<br />Name number $num is " . $edit_name{$num} ); } foreach my $num ( sort { $a <=> $b } keys %edit_type ) { $m->out( "<br />Type number $num is " . $edit_type{$num} ); }

        Of course the name and type might be related! In which case you might consider the following:

        my %edit = (); foreach my $key ( keys %ARGS ) { if ( $key =~ m/^edit_([^_]+)_(\d+)$/ ) { $edit{$2}->{$1} = $ARGS{$key}; } } # now %edit contains a hash of rows. In each row # is the type and name fields. e.g. # %edit = ( 1 => { name => 'John', type => 'student' }, # 2 => { name => 'Lisa', type => 'teacher' } # ); $m->out( "<table>" ); foreach my $row ( sort { $a <=> $b } keys %edit ) { if ( ! ( exists( $edit{$row}->{name} && exists( $edit{$row}->{type} ) ) { die( "Missing field for row $row" ); } $m->out( "<tr><td>" . $edit{$row}->{name} . "</td>" . "<td> . $edit{$row}->{type} . "</td></tr>" ); } $m->out( "</table>" );

        updated: cleaned up code