views:

268

answers:

1

I'm creating a web page to select some options from a CSV file:

CSV File Sample:

Time,h1,h2,h3,....
00:00:00,n1,n2,n3.....
.....so on


h -> header
n -> numbers

Below is the Perl code subroutine I have written to filter the header and values and return:

sub TimeData
{
    use Text::CSV;
    my @time;
    my @data;
    my ($csv_file, $type) = @_;
    open(my $csv_fh, '<', $csv_file) or die $!;
    my $parser = Text::CSV->new();
    $parser->column_names( $parser->getline($csv_fh) );
    while ( defined( my $hr = $parser->getline_hr($csv_fh) ) )
    {
        push @time, $hr->{Time};
        push @data, $hr->{$type};   
    }

    return (@time, @data);
}

I want to create a page where the input field has a drop down menu with the lists of h1, h2, h3, etc. The selected header value can be used as a input in another Perl script. Can anyone please suggest some code to get this done.

+3  A: 

Note that your return statement is problematic: The two arrays will be flattened into one and the calling code will not be able to assign the return values to two separate arrays. If you want to keep the spirit of that interface, you should return references to those arrays. See perldoc perlsub:

A return statement may be used to exit a subroutine, optionally specifying the returned value, which will be evaluated in the appropriate context (list, scalar, or void) depending on the context of the subroutine call. ... If you return one or more aggregates (arrays and hashes), these will be flattened together into one large indistinguishable list.

Using split because the computer I am typing this on has neither Text::CSV nor Text::xSV].

#!/usr/bin/perl

use strict; use warnings;

my (@header) = map { chomp; split /,/} scalar <DATA>;

while ( my $line = <DATA> ) {
    last unless $line =~ /\S/;
    chomp $line;
    my (@values) = split /,/, $line;
    print "<select>\n";
    for (my $i = 1; $i < @header; $i += 1) {
        printf qq{<option name="%s" value="%s">%s = %s</option>\n},
               $header[$i], $values[$i], $header[$i], $values[$i];
    }
    print "</select>\n";
}

__DATA__
Time,h1,h2,h3
00:00:00,n1,n2,n3

Now, if I were doing something like this, I would separate the part where I read the data and where I generate the <SELECT></SELECT> and use a template based approach for the latter. Here is an example:

#!/usr/bin/perl

use strict; use warnings;

use HTML::Template;
use List::AllUtils qw( each_arrayref );

my $select_html = <<EO_HTML;
<select>
<TMPL_LOOP OPTIONS>
<option name="<TMPL_VAR HEADER>"
value="<TMPL_VAR VALUE>"><TMPL_VAR HEADER> = <TMPL_VAR VALUE></option>
</TMPL_LOOP>
</select>
EO_HTML

my @headers = qw(h1 h2 h3);
# Stand-in for rows you read from the CSV file
my @values  = ( [qw(a1 a2 a3)], [qw(b1 b2 b3)] );

print make_select(\$select_html, \@headers, $_)->output for @values;

sub make_select {
    my ($html, $headers, $values) = @_;
    my $tmpl = HTML::Template->new(scalarref => $html);

    my @options;

    my $it = each_arrayref($headers, $values);
    while ( my ($h, $v) = $it->() ) {
        push @options, { HEADER => $h, VALUE => $v };
    }
    $tmpl->param(OPTIONS => \@options);
    return $tmpl;
}

Output:

<select>

<option name="h1"
value="a1">h1 = a1</option>

<option name="h2"
value="a2">h2 = a2</option>

<option name="h3"
value="a3">h3 = a3</option>

</select>
<select>

<option name="h1"
value="b1">h1 = b1</option>

<option name="h2"
value="b2">h2 = b2</option>

<option name="h3"
value="b3">h3 = b3</option>

</select>
Sinan Ünür
+1 for a reasonable interpretation of the question
Adam Bellaire
Don't forget to escape HTML in the attribute values and inline text.
John Siracusa