package IO::CSVHeaderFile; # $Id: CSVHeaderFile.pm,v 1.1.1.1 2004/11/20 22:21:02 vasek Exp $ use strict; use Text::CSV_XS; use IO::File; use vars qw(@ISA @EXPORT $VERSION); use Exporter; use Carp; @ISA = qw(IO::File Exporter); @EXPORT = qw( ); $VERSION = '0.03'; sub open { my $self = shift; my $args = {}; $args = pop @_ if ref($_[$#_]) eq 'HASH'; $args->{eol}|= "\n"; my $csv = Text::CSV_XS->new($args); my $mode; if(@_ > 1){ croak 'usage: $fh->open(FILENAME [ ,< > >> ][,CSVOPT])' if $_[2] =~ /^\d+$/; $mode = IO::Handle::_open_mode_string($_[1]); }else{ $mode = $_[0]; $mode =~ s/^(\+?<|>>?)(.*)$/$1/ or croak 'usage: $fh->open(FILENAME [,< > >> ][,CSVOPT])'; } my ($fh, $firstline); if($mode =~ /^<$/){ $fh = $self->SUPER::open( @_ ) or return; unless($args->{noheader}){ unless( $firstline = $self->getline ){ $self->close; return; } $csv->parse($firstline) and $args->{col} = [ $csv->fields ] unless $args->{col}; } unless(${*$self}{io_csvheaderfile_cols} = $args->{col}){ $self->close; croak "IO::CSVHeaderFile: Can't find the column names in '$_[0]'"; return; } }elsif( $mode =~ /^>>?$/){ unless(${*$self}{io_csvheaderfile_cols} = $args->{col}){ $self->close; croak "IO::CSVHeaderFile: Can't find the column names in '$_[0]'"; return; } $fh = $self->SUPER::open( @_ ) or return; $csv->print($self, $args->{col}) unless $mode =~ /^>>$/ or $args->{noheader}; }else{ croak "IO::CSVHeaderFile: Invalid mode '$mode'"; return; } ${*$self}{io_csvheaderfile_csv} = $csv; $fh } sub csv_read{ my $self = shift; my $line = $self->getline() or return; my @result = (); if( ${*$self}{io_csvheaderfile_csv}->parse($line) ){ my @cols = ${*$self}{io_csvheaderfile_csv}->fields; my $colnames = ${*$self}{io_csvheaderfile_cols}; my $avail_cols = (@cols > @$colnames)? @$colnames : @cols; for(my $i = 0; $i < $avail_cols; $i++){ push @result, $colnames->[$i] => $cols[$i]; } } wantarray? @result : { @result } } sub csv_print{ my $self = shift; return undef unless @_; my $rec = $_[0]; my @columns = (); my $colnames = ${*$self}{io_csvheaderfile_cols}; unless( ref $rec ){ my %map = (); for(my $i = 0; $i < @$colnames; $i++){ $map{$colnames->[$i]} = [] unless exists $map{$colnames->[$i]}; push @{$map{$colnames->[$i]}}, $i; } while ( my ($key, $value) = splice(@_, 0, 2) ) { my $idx = $map{$key} or next; $columns[$idx->[0]] = $value; shift @$idx if @$idx > 1; } }elsif( ref ($rec) eq 'HASH' ){ push( @columns, $rec->{$_}) foreach (@$colnames); }elsif( ref ($rec) eq 'ARRAY' ){ for( my $i = 0; $i < @$colnames; $i++){ push @columns, $rec->[$i]; } } ${*$self}{io_csvheaderfile_csv}->print($self,\@columns); } 1; __END__ # Below is stub documentation for your module. You better edit it! =head1 NAME IO::CSVHeaderFile - Perl extension for CSV Files =head1 SYNOPSIS # to read ... use IO::CSVHeaderFile; my $csv = IO::CSVHeaderFile->new( "< $filename" ); while(my $hash = $csv->csv_read ){ print "$hash->{ColHeaderTitle}\n"; } $csv->close; # or for same named columns my $csv = IO::CSVHeaderFile->new( "< $filename" ); my $data; while(@array = $csv->csv_read ){ for(my $i=0; $i< @array; $i++) { print "Column '$array[$i]': $array[$i]\n"; } print "-- end of record\n"; } $csv->close; # to write ... use IO::CSVHeaderFile; my $csv = IO::CSVHeaderFile->new( "> $filename" , {col => ['ColHeaderTitle1','ColHeaderTitle2','ColHeaderTitle1'], noheaders => 1} ); $csv->csv_print({ColHeaderTitle1 => 'First', ColHeaderTitle2 => 'Second'}) or return; $csv->csv_print(['Uno', 'Duo', 'Tre']) or return; $csv->csv_print( ColHeaderTitle1 => 'One', ColHeaderTitle2 => 'Two', ColHeaderTitle1 => 'Three with the same name as One' ) or return; $csv->close; =head1 DESCRIPTION Read from and write to csv file. =head2 EXPORT None by default. =head2 FUNCTIONS =over 4 =item csv_print RECORD | LIST Store the C into file, C can be hash reference as returned from C or an array ref with values ordered same as respctive headers in file. If LIST variant is used it can be a hash definition like a list in form of headers and values, but the header names doesn't have to be unique. This is usefull when creating a CSV file with several same named columns. =item csv_read Return the next record (hash reference in scalar context, array of header names and values in list context) from the file. Returns C if C. =cut =head1 AUTHOR Vasek Balcar, Evasek@ti.czE =head1 SEE ALSO L, L, L. =cut