I was having an issue where the import would fail and checking the item object on an afterParse event the headers of the csv were not being mapped accordingly.
It was a silly mistake on the csv or on the csv export that there was an extra space added by the end of some of the headers.
Adding a simple trim to the CsvParser solved the issue. I know it's very minor and stupid mistake, but this are hand made csvs and prone to mistakes so I want to make sure that my import won't run because of that. Couldn't find any other way of trimming/altering the headers before the import and it was so minor that wouldn't justify a custom Parser.
| Comment | File | Size | Author |
|---|---|---|---|
| #14 | csv_headers_with_extra_space-3153083-14.patch | 788 bytes | metasim |
| #7 | csv_headers_with_extra_space_3153083_7.patch | 583 bytes | matroskeen |
| #2 | csv_headers_with_extra_space_3153083_2.patch | 633 bytes | bbombachini |
Issue fork feeds-3153083
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
bbombachiniComment #3
bbombachiniComment #4
jamesdixon commentedI guess a tamper trim plugin wouldn't work on this because it's the headers of the CSV file.
@megachriz: Do you think we should always trim headers or would that mess up some use cases?
Comment #5
megachrizI think trimming the CSV source columns when entering them in the user interface is a good idea.
Trimming the CSV column names during parsing should then happen as well.
This needs a test to ensure that a CSV file with extra spaces in the column names can be imported without issues. The test could be added to the existing class
\Drupal\Tests\feeds\Kernel\Feeds\Parser\CsvParserTest.Comment #6
jamesdixon commentedGreat, we could call it something like trimColumnNameTest().
Comment #7
matroskeenThis is just a re-roll for the latest module version.
Comment #10
megachrizI've written some tests. I did it on mobile though (via gitlab web IDE), so let's see how that goes.
Comment #12
gomez_in_the_south commentedThe commit I added was just to pull in the latest dev branch changes and fix the associated merge conflict.
The new tests seem to still be failing, though I didn't piece together what may need to be changed in the CSV Parser to resolve this.
Comment #13
megachrizI think this is now good enough to test and review.
Comment #14
metasimrerolling the patch for 3.0
Comment #15
benstallings commentedClaude Code says, re patch #14:
Two bugs introduced
1. Null coalescing (??) replaced with truthy check — changes behavior for missing headers.
?? triggers only when $header[$delta] is null or undefined. The replacement ?: (truthy check) also triggers when the value is "" (empty string), "0", or false. A CSV header column literally named "0" would be silently replaced with the numeric delta index. More practically, if a header is an empty string, the old code would use "" as the key; the new code uses the numeric index, changing which source the column maps to.
2. PHP warning when header index doesn't exist.
$header[$delta] ?? $delta safely handles the case where $header[$delta] is undefined (no warning). The replacement $header[$delta] ? ... will emit an Undefined array key warning in PHP 8.x when $delta exceeds the header array length (which happens when a data row has more columns than the header row).
The right fix
Keep ?? for safety and add trim():
$key = isset($header[$delta]) ? trim($header[$delta]) : $delta;Or more concisely:
$key = trim($header[$delta] ?? '') ?: $delta;Note also that trimming should arguably happen once when the header is read (in CsvFileParser::getHeader() or right after line 63), not on every row iteration. And the source mapping at line 43 already trims source values (trim(strval($info['value']))), so if the header is trimmed too, they'd match consistently.
Verdict
The idea is right — whitespace in CSV headers should be trimmed — but the implementation introduces two regressions. Use isset() + trim() instead of replacing the null coalescing operator, and consider trimming at the header level rather than per-row.
Comment #16
benstallings commentedComment #17
benstallings commented