X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FHelper%2FCsv.pm;h=3132b284699a3e4b756bc9386dad1a48e65ee784;hb=0b542b2592c077957d9ccc08ca0cf84886e2b1d2;hp=5aac00b486f421939f3c4149d552cc7c5ad95ee9;hpb=bfb0d001f8c2dc372276c4483fdb896eeb79ff42;p=kivitendo-erp.git diff --git a/SL/Helper/Csv.pm b/SL/Helper/Csv.pm index 5aac00b48..3132b2846 100644 --- a/SL/Helper/Csv.pm +++ b/SL/Helper/Csv.pm @@ -6,14 +6,15 @@ use warnings; use Carp; use IO::File; use Params::Validate qw(:all); -use Text::CSV; +use Text::CSV_XS; use Rose::Object::MakeMethods::Generic scalar => [ qw( file encoding sep_char quote_char escape_char header profile class - numberformat dateformat ignore_unknown_columns _io _csv _objects _parsed - _data _errors + numberformat dateformat ignore_unknown_columns strict_profile _io _csv + _objects _parsed _data _errors ) ]; use SL::Helper::Csv::Dispatcher; +use SL::Helper::Csv::Error; # public interface @@ -31,13 +32,14 @@ sub new { numberformat => 0, dateformat => 0, ignore_unknown_columns => 0, + strict_profile => 0, }); my $self = bless {}, $class; $self->$_($params{$_}) for keys %params; $self->_io(IO::File->new); - $self->_csv(Text::CSV->new({ + $self->_csv(Text::CSV_XS->new({ binary => 1, sep_char => $self->sep_char, quote_char => $self->quote_char, @@ -97,17 +99,20 @@ sub _open_file { sub _check_header { my ($self, %params) = @_; - return $self->header if $self->header; + my $header = $self->header; - my $header = $self->_csv->getline($self->_io); + if (! $header) { + $header = $self->_csv->getline($self->_io); - $self->_push_error([ - $self->_csv->error_input, - $self->_csv->error_diag, - 0, - ]) unless $header; + $self->_push_error([ + $self->_csv->error_input, + $self->_csv->error_diag, + 0, + ]) unless $header; + } - $self->header($header); + return unless $header; + return $self->header([ map { lc } @$header ]); } sub _parse_data { @@ -118,18 +123,19 @@ sub _parse_data { while (1) { my $row = $self->_csv->getline($self->_io); - last if $self->_csv->eof; if ($row) { my %hr; @hr{@{ $self->header }} = @$row; push @data, \%hr; } else { + last if $self->_csv->eof; push @errors, [ $self->_csv->error_input, $self->_csv->error_diag, $self->_io->input_line_number, ]; } + last if $self->_csv->eof; } $self->_data(\@data); @@ -180,7 +186,7 @@ sub _guess_encoding { sub _push_error { my ($self, @errors) = @_; - my @new_errors = ($self->errors, @errors); + my @new_errors = ($self->errors, map { SL::Helper::Csv::Error->new(@$_) } @errors); $self->_errors(\@new_errors); } @@ -341,21 +347,23 @@ and the return value used instead of the line itself. If set, the import will ignore unkown header columns. Useful for lazy imports, but deactivated by default. +=item C + +If set, all columns to be parsed must be specified in C. Every header +field not listed there will be treated like an unknown column. + =back =head1 ERROR HANDLING After parsing a file all errors will be accumulated into C. +Each entry is an object with the following attributes: -Each entry is an arrayref with the following structure: - - [ - 0 offending raw input, - 1 Text::CSV error code if Text:CSV signalled an error, 0 else, - 2 error diagnostics, - 3 position in line, - 4 estimated line in file, - ] + raw_input: offending raw input, + code: Text::CSV error code if Text:CSV signalled an error, 0 else, + diag: error diagnostics, + line: position in line, + col: estimated line in file, Note that the last entry can be off, but will give an estimate.