diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index b3a84bf70..748cdd306 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -375,7 +375,15 @@ class Ods extends BaseReader foreach ($childNode->childNodes as $cellData) { if ($this->getReadFilter() !== null) { if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { - ++$columnID; + if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { + $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated'); + } else { + $colRepeats = 1; + } + + for ($i = 0; $i < $colRepeats; ++$i) { + ++$columnID; + } continue; } diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/RepeatedColumnsTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/RepeatedColumnsTest.php new file mode 100644 index 000000000..1b477ff6c --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/RepeatedColumnsTest.php @@ -0,0 +1,41 @@ +reader = new Ods(); + } + + public function testDefinedNames(): void + { + $this->reader->setReadFilter( + new class () implements IReadFilter { + public function readCell($columnAddress, $row, $worksheetName = ''): bool + { + return in_array($columnAddress, ['A', 'C', 'E', 'G', 'J', 'K'], true); + } + } + ); + $spreadsheet = $this->reader->load('tests/data/Reader/Ods/RepeatedCells.ods'); + $worksheet = $spreadsheet->getActiveSheet(); + + self::assertEquals('TestA', $worksheet->getCell('A1')->getValue()); + self::assertNull($worksheet->getCell('C1')->getValue()); + self::assertEquals('TestE', $worksheet->getCell('E1')->getValue()); + self::assertEquals('TestG', $worksheet->getCell('G1')->getValue()); + self::assertEquals('A', $worksheet->getCell('J1')->getValue()); + self::assertEquals('TestK', $worksheet->getCell('K1')->getValue()); + } +} diff --git a/tests/data/Reader/Ods/RepeatedCells.ods b/tests/data/Reader/Ods/RepeatedCells.ods new file mode 100644 index 000000000..46ecc4535 Binary files /dev/null and b/tests/data/Reader/Ods/RepeatedCells.ods differ