From 9708d72ee125baecae14afbc195fb099edd3459f Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Tue, 8 Jul 2025 12:52:55 -0700 Subject: [PATCH 1/2] Ods Reader Process Nested table-row Fix #4528. Fix #2507. Ods Reader expects `table:table-row` to descend directly from `table:table`. But it turns out that it can be nested under `table:table-header-rows`, `table:table-rows`, or `table:table-row-group`. Similar considerations apply to `table:table-column`. Ods Reader is changed to process the nesting tags, and therefore the nested tags underneath them. This is a major change, but it doesn't seem to have broken any existing tests or samples. No attempt is made to add any of the nesting tags in Ods Writer. It should be noted that 4528 has an additional problem, which has been reported as issue #4530. It is not fixed by this PR. --- src/PhpSpreadsheet/Reader/Ods.php | 842 ++++++++++++------ .../Reader/Ods/NestedTableRowTest.php | 42 + tests/data/Reader/Ods/issue.2507.ods | Bin 0 -> 20923 bytes tests/data/Reader/Ods/issue.4528.ods | Bin 0 -> 45138 bytes 4 files changed, 591 insertions(+), 293 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Ods/NestedTableRowTest.php create mode 100644 tests/data/Reader/Ods/issue.2507.ods create mode 100644 tests/data/Reader/Ods/issue.4528.ods diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index 420ae2f7b5..97f6a45b2e 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -354,331 +354,589 @@ public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Sp continue; } - $key = $childNode->nodeName; - - // Remove ns from node name - if (str_contains($key, ':')) { - $keyChunks = explode(':', $key); - $key = array_pop($keyChunks); - } + $key = self::extractNodeName($childNode->nodeName); switch ($key) { case 'table-header-rows': - /// TODO :: Figure this out. This is only a partial implementation I guess. - // ($rowData it's not used at all and I'm not sure that PHPExcel - // has an API for this) - -// foreach ($rowData as $keyRowData => $cellData) { -// $rowData = $cellData; -// break; -// } + case 'table-rows': + $this->processTableHeaderRows( + $childNode, + $tableNs, + $rowID, + $worksheetName, + $officeNs, + $textNs, + $xlinkNs, + $spreadsheet + ); + + break; + case 'table-row-group': + $this->processTableRowGroup( + $childNode, + $tableNs, + $rowID, + $worksheetName, + $officeNs, + $textNs, + $xlinkNs, + $spreadsheet + ); + + break; + case 'table-header-columns': + case 'table-columns': + $this->processTableHeaderColumns( + $childNode, + $tableNs, + $columnWidths, + $tableColumnIndex, + $spreadsheet + ); + + break; + case 'table-column-group': + $this->processTableColumnGroup( + $childNode, + $tableNs, + $columnWidths, + $tableColumnIndex, + $spreadsheet + ); + break; case 'table-column': - if ($childNode->hasAttributeNS($tableNs, 'number-columns-repeated')) { - $rowRepeats = (int) $childNode->getAttributeNS($tableNs, 'number-columns-repeated'); - } else { - $rowRepeats = 1; - } - $tableStyleName = $childNode->getAttributeNS($tableNs, 'style-name'); - if (isset($columnWidths[$tableStyleName])) { - $columnWidth = new HelperDimension($columnWidths[$tableStyleName]); - $tableColumnString = Coordinate::stringFromColumnIndex($tableColumnIndex); - for ($rowRepeats2 = $rowRepeats; $rowRepeats2 > 0; --$rowRepeats2) { - /** @var string $tableColumnString */ - $spreadsheet->getActiveSheet() - ->getColumnDimension($tableColumnString) - ->setWidth($columnWidth->toUnit('cm'), 'cm'); - ++$tableColumnString; - } - } - $tableColumnIndex += $rowRepeats; + $this->processTableColumn( + $childNode, + $tableNs, + $columnWidths, + $tableColumnIndex, + $spreadsheet + ); break; case 'table-row': - if ($childNode->hasAttributeNS($tableNs, 'number-rows-repeated')) { - $rowRepeats = (int) $childNode->getAttributeNS($tableNs, 'number-rows-repeated'); - } else { - $rowRepeats = 1; + $this->processTableRow( + $childNode, + $tableNs, + $rowID, + $worksheetName, + $officeNs, + $textNs, + $xlinkNs, + $spreadsheet + ); + + break; + } + } + $pageSettings->setVisibilityForWorksheet( + $spreadsheet->getActiveSheet(), + $worksheetStyleName + ); + $pageSettings->setPrintSettingsForWorksheet( + $spreadsheet->getActiveSheet(), + $worksheetStyleName + ); + ++$worksheetID; + } + + $autoFilterReader->read($workbookData); + $definedNameReader->read($workbookData); + } + $spreadsheet->setActiveSheetIndex(0); + + if ($zip->locateName('settings.xml') !== false) { + $this->processSettings($zip, $spreadsheet); + } + + // Return + return $spreadsheet; + } + + private function processTableHeaderRows( + DOMElement $childNode, + string $tableNs, + int &$rowID, + string $worksheetName, + string $officeNs, + string $textNs, + string $xlinkNs, + Spreadsheet $spreadsheet + ): void { + foreach ($childNode->childNodes as $grandchildNode) { + /** @var DOMElement $grandchildNode */ + $grandkey = self::extractNodeName($grandchildNode->nodeName); + switch ($grandkey) { + case 'table-row': + $this->processTableRow( + $grandchildNode, + $tableNs, + $rowID, + $worksheetName, + $officeNs, + $textNs, + $xlinkNs, + $spreadsheet + ); + + break; + } + } + } + + private function processTableRowGroup( + DOMElement $childNode, + string $tableNs, + int &$rowID, + string $worksheetName, + string $officeNs, + string $textNs, + string $xlinkNs, + Spreadsheet $spreadsheet + ): void { + foreach ($childNode->childNodes as $grandchildNode) { + /** @var DOMElement $grandchildNode */ + $grandkey = self::extractNodeName($grandchildNode->nodeName); + switch ($grandkey) { + case 'table-row': + $this->processTableRow( + $grandchildNode, + $tableNs, + $rowID, + $worksheetName, + $officeNs, + $textNs, + $xlinkNs, + $spreadsheet + ); + + break; + case 'table-header-rows': + case 'table-rows': + $this->processTableHeaderRows( + $grandchildNode, + $tableNs, + $rowID, + $worksheetName, + $officeNs, + $textNs, + $xlinkNs, + $spreadsheet + ); + + break; + case 'table-row-group': + $this->processTableRowGroup( + $grandchildNode, + $tableNs, + $rowID, + $worksheetName, + $officeNs, + $textNs, + $xlinkNs, + $spreadsheet + ); + + break; + } + } + } + + private function processTableRow( + DOMElement $childNode, + string $tableNs, + int &$rowID, + string $worksheetName, + string $officeNs, + string $textNs, + string $xlinkNs, + Spreadsheet $spreadsheet + ): void { + if ($childNode->hasAttributeNS($tableNs, 'number-rows-repeated')) { + $rowRepeats = (int) $childNode->getAttributeNS($tableNs, 'number-rows-repeated'); + } else { + $rowRepeats = 1; + } + + $columnID = 'A'; + /** @var DOMElement|DOMText $cellData */ + foreach ($childNode->childNodes as $cellData) { + if ($cellData instanceof DOMText) { + continue; // should just be whitespace + } + if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { + 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; + } + + // Initialize variables + $formatting = $hyperlink = null; + $hasCalculatedValue = false; + $cellDataFormula = ''; + $cellDataType = ''; + $cellDataRef = ''; + + if ($cellData->hasAttributeNS($tableNs, 'formula')) { + $cellDataFormula = $cellData->getAttributeNS($tableNs, 'formula'); + $hasCalculatedValue = true; + } + if ($cellData->hasAttributeNS($tableNs, 'number-matrix-columns-spanned')) { + if ($cellData->hasAttributeNS($tableNs, 'number-matrix-rows-spanned')) { + $cellDataType = 'array'; + $arrayRow = (int) $cellData->getAttributeNS($tableNs, 'number-matrix-rows-spanned'); + $arrayCol = (int) $cellData->getAttributeNS($tableNs, 'number-matrix-columns-spanned'); + $lastRow = $rowID + $arrayRow - 1; + $lastCol = $columnID; + while ($arrayCol > 1) { + ++$lastCol; + --$arrayCol; + } + $cellDataRef = "$columnID$rowID:$lastCol$lastRow"; + } + } + + // Annotations + $annotation = $cellData->getElementsByTagNameNS($officeNs, 'annotation'); + + if ($annotation->length > 0 && $annotation->item(0) !== null) { + $textNode = $annotation->item(0)->getElementsByTagNameNS($textNs, 'p'); + $textNodeLength = $textNode->length; + $newLineOwed = false; + for ($textNodeIndex = 0; $textNodeIndex < $textNodeLength; ++$textNodeIndex) { + $textNodeItem = $textNode->item($textNodeIndex); + if ($textNodeItem !== null) { + $text = $this->scanElementForText($textNodeItem); + if ($newLineOwed) { + $spreadsheet->getActiveSheet() + ->getComment($columnID . $rowID) + ->getText() + ->createText("\n"); + } + $newLineOwed = true; + + $spreadsheet->getActiveSheet() + ->getComment($columnID . $rowID) + ->getText() + ->createText( + $this->parseRichText($text) + ); + } + } + } + + // Content + + /** @var DOMElement[] $paragraphs */ + $paragraphs = []; + + foreach ($cellData->childNodes as $item) { + /** @var DOMElement $item */ + + // Filter text:p elements + if ($item->nodeName == 'text:p') { + $paragraphs[] = $item; + } + } + + if (count($paragraphs) > 0) { + // Consolidate if there are multiple p records (maybe with spans as well) + $dataArray = []; + + // Text can have multiple text:p and within those, multiple text:span. + // text:p newlines, but text:span does not. + // Also, here we assume there is no text data is span fields are specified, since + // we have no way of knowing proper positioning anyway. + + foreach ($paragraphs as $pData) { + $dataArray[] = $this->scanElementForText($pData); + } + $allCellDataText = implode("\n", $dataArray); + + $type = $cellData->getAttributeNS($officeNs, 'value-type'); + + switch ($type) { + case 'string': + $type = DataType::TYPE_STRING; + $dataValue = $allCellDataText; + + foreach ($paragraphs as $paragraph) { + $link = $paragraph->getElementsByTagNameNS($textNs, 'a'); + if ($link->length > 0 && $link->item(0) !== null) { + $hyperlink = $link->item(0)->getAttributeNS($xlinkNs, 'href'); } + } - $columnID = 'A'; - /** @var DOMElement|DOMText $cellData */ - foreach ($childNode->childNodes as $cellData) { - if ($cellData instanceof DOMText) { - continue; // should just be whitespace - } - if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { - 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; - } + break; + case 'boolean': + $type = DataType::TYPE_BOOL; + $dataValue = ($cellData->getAttributeNS($officeNs, 'boolean-value') === 'true') ? true : false; + + break; + case 'percentage': + $type = DataType::TYPE_NUMERIC; + $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); + + // percentage should always be float + //if (floor($dataValue) == $dataValue) { + // $dataValue = (int) $dataValue; + //} + $formatting = NumberFormat::FORMAT_PERCENTAGE_00; + + break; + case 'currency': + $type = DataType::TYPE_NUMERIC; + $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); + + if (floor($dataValue) == $dataValue) { + $dataValue = (int) $dataValue; + } + $formatting = NumberFormat::FORMAT_CURRENCY_USD_INTEGER; - // Initialize variables - $formatting = $hyperlink = null; - $hasCalculatedValue = false; - $cellDataFormula = ''; - $cellDataType = ''; - $cellDataRef = ''; + break; + case 'float': + $type = DataType::TYPE_NUMERIC; + $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); - if ($cellData->hasAttributeNS($tableNs, 'formula')) { - $cellDataFormula = $cellData->getAttributeNS($tableNs, 'formula'); - $hasCalculatedValue = true; - } - if ($cellData->hasAttributeNS($tableNs, 'number-matrix-columns-spanned')) { - if ($cellData->hasAttributeNS($tableNs, 'number-matrix-rows-spanned')) { - $cellDataType = 'array'; - $arrayRow = (int) $cellData->getAttributeNS($tableNs, 'number-matrix-rows-spanned'); - $arrayCol = (int) $cellData->getAttributeNS($tableNs, 'number-matrix-columns-spanned'); - $lastRow = $rowID + $arrayRow - 1; - $lastCol = $columnID; - while ($arrayCol > 1) { - ++$lastCol; - --$arrayCol; - } - $cellDataRef = "$columnID$rowID:$lastCol$lastRow"; - } - } + if (floor($dataValue) == $dataValue) { + if ($dataValue == (int) $dataValue) { + $dataValue = (int) $dataValue; + } + } - // Annotations - $annotation = $cellData->getElementsByTagNameNS($officeNs, 'annotation'); - - if ($annotation->length > 0 && $annotation->item(0) !== null) { - $textNode = $annotation->item(0)->getElementsByTagNameNS($textNs, 'p'); - $textNodeLength = $textNode->length; - $newLineOwed = false; - for ($textNodeIndex = 0; $textNodeIndex < $textNodeLength; ++$textNodeIndex) { - $textNodeItem = $textNode->item($textNodeIndex); - if ($textNodeItem !== null) { - $text = $this->scanElementForText($textNodeItem); - if ($newLineOwed) { - $spreadsheet->getActiveSheet() - ->getComment($columnID . $rowID) - ->getText() - ->createText("\n"); - } - $newLineOwed = true; - - $spreadsheet->getActiveSheet() - ->getComment($columnID . $rowID) - ->getText() - ->createText($this->parseRichText($text)); - } - } - } + break; + case 'date': + $type = DataType::TYPE_NUMERIC; + $value = $cellData->getAttributeNS($officeNs, 'date-value'); + $dataValue = Date::convertIsoDate($value); + + if ($dataValue != floor($dataValue)) { + $formatting = NumberFormat::FORMAT_DATE_XLSX15 + . ' ' + . NumberFormat::FORMAT_DATE_TIME4; + } else { + $formatting = NumberFormat::FORMAT_DATE_XLSX15; + } - // Content + break; + case 'time': + $type = DataType::TYPE_NUMERIC; - /** @var DOMElement[] $paragraphs */ - $paragraphs = []; + $timeValue = $cellData->getAttributeNS($officeNs, 'time-value'); - foreach ($cellData->childNodes as $item) { - /** @var DOMElement $item */ + $dataValue = Date::PHPToExcel( + strtotime( + '01-01-1970 ' . implode(':', sscanf($timeValue, 'PT%dH%dM%dS') ?? []) + ) + ); + $formatting = NumberFormat::FORMAT_DATE_TIME4; - // Filter text:p elements - if ($item->nodeName == 'text:p') { - $paragraphs[] = $item; - } - } + break; + default: + $dataValue = null; + } + } else { + $type = DataType::TYPE_NULL; + $dataValue = null; + } - if (count($paragraphs) > 0) { - // Consolidate if there are multiple p records (maybe with spans as well) - $dataArray = []; - - // Text can have multiple text:p and within those, multiple text:span. - // text:p newlines, but text:span does not. - // Also, here we assume there is no text data is span fields are specified, since - // we have no way of knowing proper positioning anyway. - - foreach ($paragraphs as $pData) { - $dataArray[] = $this->scanElementForText($pData); - } - $allCellDataText = implode("\n", $dataArray); - - $type = $cellData->getAttributeNS($officeNs, 'value-type'); - - switch ($type) { - case 'string': - $type = DataType::TYPE_STRING; - $dataValue = $allCellDataText; - - foreach ($paragraphs as $paragraph) { - $link = $paragraph->getElementsByTagNameNS($textNs, 'a'); - if ($link->length > 0 && $link->item(0) !== null) { - $hyperlink = $link->item(0)->getAttributeNS($xlinkNs, 'href'); - } - } - - break; - case 'boolean': - $type = DataType::TYPE_BOOL; - $dataValue = ($cellData->getAttributeNS($officeNs, 'boolean-value') === 'true') ? true : false; - - break; - case 'percentage': - $type = DataType::TYPE_NUMERIC; - $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); - - // percentage should always be float - //if (floor($dataValue) == $dataValue) { - // $dataValue = (int) $dataValue; - //} - $formatting = NumberFormat::FORMAT_PERCENTAGE_00; - - break; - case 'currency': - $type = DataType::TYPE_NUMERIC; - $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); - - if (floor($dataValue) == $dataValue) { - $dataValue = (int) $dataValue; - } - $formatting = NumberFormat::FORMAT_CURRENCY_USD_INTEGER; - - break; - case 'float': - $type = DataType::TYPE_NUMERIC; - $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); - - if (floor($dataValue) == $dataValue) { - if ($dataValue == (int) $dataValue) { - $dataValue = (int) $dataValue; - } - } - - break; - case 'date': - $type = DataType::TYPE_NUMERIC; - $value = $cellData->getAttributeNS($officeNs, 'date-value'); - $dataValue = Date::convertIsoDate($value); - - if ($dataValue != floor($dataValue)) { - $formatting = NumberFormat::FORMAT_DATE_XLSX15 - . ' ' - . NumberFormat::FORMAT_DATE_TIME4; - } else { - $formatting = NumberFormat::FORMAT_DATE_XLSX15; - } - - break; - case 'time': - $type = DataType::TYPE_NUMERIC; - - $timeValue = $cellData->getAttributeNS($officeNs, 'time-value'); - - $dataValue = Date::PHPToExcel( - strtotime( - '01-01-1970 ' . implode(':', sscanf($timeValue, 'PT%dH%dM%dS') ?? []) - ) - ); - $formatting = NumberFormat::FORMAT_DATE_TIME4; - - break; - default: - $dataValue = null; - } - } else { - $type = DataType::TYPE_NULL; - $dataValue = null; - } + if ($hasCalculatedValue) { + $type = DataType::TYPE_FORMULA; + $cellDataFormula = substr($cellDataFormula, strpos($cellDataFormula, ':=') + 1); + $cellDataFormula = FormulaTranslator::convertToExcelFormulaValue($cellDataFormula); + } - if ($hasCalculatedValue) { - $type = DataType::TYPE_FORMULA; - $cellDataFormula = substr($cellDataFormula, strpos($cellDataFormula, ':=') + 1); - $cellDataFormula = FormulaTranslator::convertToExcelFormulaValue($cellDataFormula); - } + if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { + $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated'); + } else { + $colRepeats = 1; + } - if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { - $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated'); - } else { - $colRepeats = 1; - } + if ($type !== null) { // @phpstan-ignore-line + for ($i = 0; $i < $colRepeats; ++$i) { + if ($i > 0) { + ++$columnID; + } - if ($type !== null) { // @phpstan-ignore-line - for ($i = 0; $i < $colRepeats; ++$i) { - if ($i > 0) { - ++$columnID; - } - - if ($type !== DataType::TYPE_NULL) { - for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) { - $rID = $rowID + $rowAdjust; - - $cell = $spreadsheet->getActiveSheet() - ->getCell($columnID . $rID); - - // Set value - if ($hasCalculatedValue) { - $cell->setValueExplicit($cellDataFormula, $type); - if ($cellDataType === 'array') { - $cell->setFormulaAttributes(['t' => 'array', 'ref' => $cellDataRef]); - } - } elseif ($type !== '' || $dataValue !== null) { - $cell->setValueExplicit($dataValue, $type); - } - - if ($hasCalculatedValue) { - $cell->setCalculatedValue($dataValue, $type === DataType::TYPE_NUMERIC); - } - - // Set other properties - if ($formatting !== null) { - $spreadsheet->getActiveSheet() - ->getStyle($columnID . $rID) - ->getNumberFormat() - ->setFormatCode($formatting); - } else { - $spreadsheet->getActiveSheet() - ->getStyle($columnID . $rID) - ->getNumberFormat() - ->setFormatCode(NumberFormat::FORMAT_GENERAL); - } - - if ($hyperlink !== null) { - if ($hyperlink[0] === '#') { - $hyperlink = 'sheet://' . substr($hyperlink, 1); - } - $cell->getHyperlink() - ->setUrl($hyperlink); - } - } - } - } + if ($type !== DataType::TYPE_NULL) { + for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) { + $rID = $rowID + $rowAdjust; + + $cell = $spreadsheet->getActiveSheet() + ->getCell($columnID . $rID); + + // Set value + if ($hasCalculatedValue) { + $cell->setValueExplicit($cellDataFormula, $type); + if ($cellDataType === 'array') { + $cell->setFormulaAttributes(['t' => 'array', 'ref' => $cellDataRef]); } + } elseif ($type !== '' || $dataValue !== null) { + $cell->setValueExplicit($dataValue, $type); + } - // Merged cells - $this->processMergedCells($cellData, $tableNs, $type, $columnID, $rowID, $spreadsheet); + if ($hasCalculatedValue) { + $cell->setCalculatedValue($dataValue, $type === DataType::TYPE_NUMERIC); + } - ++$columnID; + // Set other properties + if ($formatting !== null) { + $spreadsheet->getActiveSheet() + ->getStyle($columnID . $rID) + ->getNumberFormat() + ->setFormatCode($formatting); + } else { + $spreadsheet->getActiveSheet() + ->getStyle($columnID . $rID) + ->getNumberFormat() + ->setFormatCode(NumberFormat::FORMAT_GENERAL); } - $rowID += $rowRepeats; - break; + if ($hyperlink !== null) { + if ($hyperlink[0] === '#') { + $hyperlink = 'sheet://' . substr($hyperlink, 1); + } + $cell->getHyperlink() + ->setUrl($hyperlink); + } + } } } - $pageSettings->setVisibilityForWorksheet($spreadsheet->getActiveSheet(), $worksheetStyleName); - $pageSettings->setPrintSettingsForWorksheet($spreadsheet->getActiveSheet(), $worksheetStyleName); - ++$worksheetID; } - $autoFilterReader->read($workbookData); - $definedNameReader->read($workbookData); + // Merged cells + $this->processMergedCells($cellData, $tableNs, $type, $columnID, $rowID, $spreadsheet); + + ++$columnID; } - $spreadsheet->setActiveSheetIndex(0); + $rowID += $rowRepeats; + } - if ($zip->locateName('settings.xml') !== false) { - $this->processSettings($zip, $spreadsheet); + private static function extractNodeName(string $key): string + { + // Remove ns from node name + if (str_contains($key, ':')) { + $keyChunks = explode(':', $key); + $key = array_pop($keyChunks); } - // Return - return $spreadsheet; + return $key; + } + + /** + * @param string[] $columnWidths + */ + private function processTableHeaderColumns( + DOMElement $childNode, + string $tableNs, + array $columnWidths, + int &$tableColumnIndex, + Spreadsheet $spreadsheet + ): void { + foreach ($childNode->childNodes as $grandchildNode) { + /** @var DOMElement $grandchildNode */ + $grandkey = self::extractNodeName($grandchildNode->nodeName); + switch ($grandkey) { + case 'table-column': + $this->processTableColumn( + $grandchildNode, + $tableNs, + $columnWidths, + $tableColumnIndex, + $spreadsheet + ); + + break; + } + } + } + + /** + * @param string[] $columnWidths + */ + private function processTableColumnGroup( + DOMElement $childNode, + string $tableNs, + array $columnWidths, + int &$tableColumnIndex, + Spreadsheet $spreadsheet + ): void { + foreach ($childNode->childNodes as $grandchildNode) { + /** @var DOMElement $grandchildNode */ + $grandkey = self::extractNodeName($grandchildNode->nodeName); + switch ($grandkey) { + case 'table-column': + $this->processTableColumn( + $grandchildNode, + $tableNs, + $columnWidths, + $tableColumnIndex, + $spreadsheet + ); + + break; + case 'table-header-columns': + case 'table-columns': + $this->processTableHeaderColumns( + $grandchildNode, + $tableNs, + $columnWidths, + $tableColumnIndex, + $spreadsheet + ); + + break; + case 'table-column-group': + $this->processTableColumnGroup( + $grandchildNode, + $tableNs, + $columnWidths, + $tableColumnIndex, + $spreadsheet + ); + + break; + } + } + } + + /** + * @param string[] $columnWidths + */ + private function processTableColumn( + DOMElement $childNode, + string $tableNs, + array $columnWidths, + int &$tableColumnIndex, + Spreadsheet $spreadsheet + ): void { + if ($childNode->hasAttributeNS($tableNs, 'number-columns-repeated')) { + $rowRepeats = (int) $childNode->getAttributeNS($tableNs, 'number-columns-repeated'); + } else { + $rowRepeats = 1; + } + $tableStyleName = $childNode->getAttributeNS($tableNs, 'style-name'); + if (isset($columnWidths[$tableStyleName])) { + $columnWidth = new HelperDimension($columnWidths[$tableStyleName]); + $tableColumnString = Coordinate::stringFromColumnIndex($tableColumnIndex); + for ($rowRepeats2 = $rowRepeats; $rowRepeats2 > 0; --$rowRepeats2) { + /** @var string $tableColumnString */ + $spreadsheet->getActiveSheet() + ->getColumnDimension($tableColumnString) + ->setWidth($columnWidth->toUnit('cm'), 'cm'); + ++$tableColumnString; + } + } + $tableColumnIndex += $rowRepeats; } private function processSettings(ZipArchive $zip, Spreadsheet $spreadsheet): void @@ -688,9 +946,7 @@ private function processSettings(ZipArchive $zip, Spreadsheet $spreadsheet): voi $this->getSecurityScannerOrThrow() ->scan($zip->getFromName('settings.xml')) ); - //$xlinkNs = $dom->lookupNamespaceUri('xlink'); $configNs = (string) $dom->lookupNamespaceUri('config'); - //$oooNs = $dom->lookupNamespaceUri('ooo'); $officeNs = (string) $dom->lookupNamespaceUri('office'); $settings = $dom->getElementsByTagNameNS($officeNs, 'settings') ->item(0); diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/NestedTableRowTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/NestedTableRowTest.php new file mode 100644 index 0000000000..45e0646b9e --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/NestedTableRowTest.php @@ -0,0 +1,42 @@ +load($infile); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame('Atterissage', $sheet->getCell('AS1')->getValue()); + self::assertNull($sheet->getCell('AS2')->getValue()); + self::assertSame('jour', $sheet->getCell('AS3')->getValue()); + self::assertSame('=SUM(Y3:INDIRECT(CONCATENATE("Y",$C$3)))', $sheet->getCell('AS4')->getValue()); + $spreadsheet->disconnectWorksheets(); + } + + public function testTableRowGroup(): void + { + $infile = 'tests/data/Reader/Ods/issue.2507.ods'; + $reader = new OdsReader(); + $spreadsheet = $reader->load($infile); + $sheet = $spreadsheet->getActiveSheet(); + $values = $sheet->rangeToArray('B3:C7', null, false, false); + $expected = [ + ['Номенклатура', "Складское наличие,\nКол-во"], // before table-row-group + ['Квадрат 140х140мм ст.5ХНМ (т)', 0.225], // within table-row-group + ['Квадрат 200х200мм ст.3 (т)', 1.700], + ['Квадрат 210х210мм ст.65Г (т)', 0.280], + ['Квадрат 250х250мм ст.45 (т)', 0.133], + ]; + self::assertSame($expected, $values); + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/data/Reader/Ods/issue.2507.ods b/tests/data/Reader/Ods/issue.2507.ods new file mode 100644 index 0000000000000000000000000000000000000000..1475bc648ffdb9eddd458b3486566cbff36b65be GIT binary patch literal 20923 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 o5dJP=GNd4P>;LlOPyg!P{d9L3c?$5BV^B;{X5v literal 0 HcmV?d00001 From 11dc1fb67ee179f3a7e488eb9c45cdb709cf5b81 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Mon, 14 Jul 2025 23:20:41 -0700 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b8534ef61..0696724f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed -- Nothing yet. +- Ods Reader Nested table-row. [Issue #4528](https://github.com/PHPOffice/PhpSpreadsheet/issues/4528) [Issue #2507](https://github.com/PHPOffice/PhpSpreadsheet/issues/2507) [PR #4531](https://github.com/PHPOffice/PhpSpreadsheet/pull/4531) ## 2025-06-22 - 4.4.0