Revision f9f7b56e
Von Sven Schöling vor mehr als 13 Jahren hinzugefügt
SL/Helper/Csv.pm | ||
---|---|---|
8 | 8 |
use Text::CSV; |
9 | 9 |
use Params::Validate qw(:all); |
10 | 10 |
use Rose::Object::MakeMethods::Generic scalar => [ qw( |
11 |
file encoding sep_char quote_char escape_char header header_acc class
|
|
11 |
file encoding sep_char quote_char escape_char header dispatch class
|
|
12 | 12 |
numberformat dateformat _io _csv _objects _parsed _data _errors |
13 | 13 |
) ]; |
14 | 14 |
|
... | ... | |
22 | 22 |
quote_char => { default => '"' }, |
23 | 23 |
escape_char => { default => '"' }, |
24 | 24 |
header => { type => ARRAYREF, optional => 1 }, |
25 |
header_acc => { type => HASHREF, optional => 1 },
|
|
25 |
dispatch => { type => HASHREF, optional => 1 },
|
|
26 | 26 |
file => 1, |
27 | 27 |
encoding => 0, |
28 | 28 |
class => 0, |
... | ... | |
74 | 74 |
@{ $_[0]->_errors } |
75 | 75 |
} |
76 | 76 |
|
77 |
sub check_header { |
|
78 |
$_[0]->_check_header; |
|
79 |
} |
|
80 |
|
|
77 | 81 |
# private stuff |
78 | 82 |
|
79 | 83 |
sub _open_file { |
... | ... | |
96 | 100 |
$self->header($header); |
97 | 101 |
} |
98 | 102 |
|
103 |
sub _check_header_for_class { |
|
104 |
my ($self, %params) = @_; |
|
105 |
my @errors; |
|
106 |
|
|
107 |
return unless $self->class; |
|
108 |
return $self->header; |
|
109 |
|
|
110 |
for my $method (@{ $self->header }) { |
|
111 |
next if $self->class->can($self->_real_method($method)); |
|
112 |
|
|
113 |
push @errors, [ |
|
114 |
$method, |
|
115 |
undef, |
|
116 |
"header field $method is not recognized", |
|
117 |
undef, |
|
118 |
0, |
|
119 |
]; |
|
120 |
} |
|
121 |
|
|
122 |
$self->_push_error(@errors); |
|
123 |
|
|
124 |
return ! @errors; |
|
125 |
} |
|
126 |
|
|
99 | 127 |
sub _parse_data { |
100 | 128 |
my ($self, %params) = @_; |
101 | 129 |
my (@data, @errors); |
... | ... | |
120 | 148 |
} |
121 | 149 |
|
122 | 150 |
$self->_data(\@data); |
123 |
$self->_errors(\@errors);
|
|
151 |
$self->_push_error(@errors);
|
|
124 | 152 |
|
125 |
return if @errors; |
|
126 |
return \@data; |
|
153 |
return ! @errors; |
|
127 | 154 |
} |
128 | 155 |
|
129 | 156 |
sub _encode_layer { |
... | ... | |
141 | 168 |
for my $line (@{ $self->_data }) { |
142 | 169 |
push @objs, $self->class->new( |
143 | 170 |
map { |
144 |
($self->header_acc && $self->header_acc->{$_}) || $_ => $line->{$_}
|
|
171 |
$self->_real_method($_) => $line->{$_}
|
|
145 | 172 |
} grep { $_ } keys %$line |
146 | 173 |
); |
147 | 174 |
} |
... | ... | |
149 | 176 |
$self->_objects(\@objs); |
150 | 177 |
} |
151 | 178 |
|
179 |
sub _real_method { |
|
180 |
my ($self, $arg) = @_; |
|
181 |
($self->dispatch && $self->dispatch->{$arg}) || $arg; |
|
182 |
} |
|
183 |
|
|
152 | 184 |
sub _guess_encoding { |
153 | 185 |
# won't fix |
154 | 186 |
'utf-8'; |
155 | 187 |
} |
156 | 188 |
|
189 |
sub _push_error { |
|
190 |
my ($self, @errors) = @_; |
|
191 |
my @new_errors = ($self->errors, @errors); |
|
192 |
$self->_errors(\@new_errors); |
|
193 |
} |
|
194 |
|
|
157 | 195 |
|
158 | 196 |
1; |
159 | 197 |
|
... | ... | |
175 | 213 |
sep_char => ',', # default ';' |
176 | 214 |
quote_char => ''', # default '"' |
177 | 215 |
header => [qw(id text sellprice word)] # see later |
178 |
header_acc => { sellprice => 'sellprice_as_number' }
|
|
216 |
dispatch => { sellprice => 'sellprice_as_number' }
|
|
179 | 217 |
class => 'SL::DB::CsvLine', # if present, map lines to this |
180 | 218 |
) |
181 | 219 |
|
... | ... | |
191 | 229 |
most cases you will want those line to be parsed into hashes or even objects, |
192 | 230 |
so this model just skips ahead and gives you objects. |
193 | 231 |
|
194 |
Encoding autodetection is not easy, and should not be trusted. Try to avoid it if possible. |
|
232 |
Encoding autodetection is not easy, and should not be trusted. Try to avoid it |
|
233 |
if possible. |
|
195 | 234 |
|
196 | 235 |
=head1 METHODS |
197 | 236 |
|
... | ... | |
233 | 272 |
|
234 | 273 |
=item C<encoding> |
235 | 274 |
|
236 |
Encoding of the CSV file. Note that this module does not do any encoding guessing.
|
|
237 |
Know what your data ist. Defaults to utf-8. |
|
275 |
Encoding of the CSV file. Note that this module does not do any encoding |
|
276 |
guessing. Know what your data ist. Defaults to utf-8.
|
|
238 | 277 |
|
239 | 278 |
=item C<sep_char> |
240 | 279 |
|
... | ... | |
246 | 285 |
|
247 | 286 |
=item C<header> \@FIELDS |
248 | 287 |
|
249 |
can be an array of columns, in this case the first line is not used as a
|
|
288 |
Can be an array of columns, in this case the first line is not used as a
|
|
250 | 289 |
header. Empty header fields will be ignored in objects. |
251 | 290 |
|
252 |
=item C<header_acc> \%ACCESSORS
|
|
291 |
=item C<dispatch> \%ACCESSORS
|
|
253 | 292 |
|
254 | 293 |
May be used to map header fields to custom accessors. Example: |
255 | 294 |
|
... | ... | |
273 | 312 |
|
274 | 313 |
[ |
275 | 314 |
offending raw input, |
276 |
Text::CSV error code if present,
|
|
277 |
Text::CSV error diagnostics if present,
|
|
315 |
Text::CSV error code if T:C error, 0 else,
|
|
316 |
error diagnostics,
|
|
278 | 317 |
position in line, |
279 | 318 |
estimated line in file, |
280 | 319 |
] |
... | ... | |
294 | 333 |
|
295 | 334 |
Encoding errors are not dealt with properly. |
296 | 335 |
|
297 |
=item * |
|
298 |
|
|
299 |
Errors are not gathered. |
|
300 |
|
|
301 | 336 |
=back |
302 | 337 |
|
338 |
=head1 TODO |
|
339 |
|
|
340 |
Dispatch to child objects, like this: |
|
341 |
|
|
342 |
$csv = SL::Helper::Csv->new( |
|
343 |
file => ... |
|
344 |
class => SL::DB::Part, |
|
345 |
dispatch => [ |
|
346 |
makemodel => { |
|
347 |
make_1 => make, |
|
348 |
model_1 => model, |
|
349 |
}, |
|
350 |
makemodel => { |
|
351 |
make_2 => make, |
|
352 |
model_2 => model, |
|
353 |
}, |
|
354 |
] |
|
355 |
); |
|
356 |
|
|
303 | 357 |
=head1 AUTHOR |
304 | 358 |
|
305 | 359 |
Sven Schöling E<lt>s.schoeling@linet-services.deE<gt> |
Auch abrufbar als: Unified diff
SL/Helper/Csv.pm: header_acc umbenannt in dispatch, Doku, check_header