A Bit More Flexibility

And some more tests.
This commit is contained in:
oleibman
2026-03-09 14:50:04 -07:00
parent 7f0985bce0
commit 75680f4612
5 changed files with 76 additions and 13 deletions
+40 -12
View File
@@ -347,6 +347,7 @@ class Ods extends BaseReader
$xlinkNs = (string) $dom->lookupNamespaceUri('xlink');
$automaticStyle0 = $this->readDataOnly ? null : $dom->getElementsByTagNameNS($officeNs, 'styles')->item(0);
$this->processSomeNumberFormats($automaticStyle0, $numberNs, $styleNs);
$automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($styleNs, 'default-style');
foreach ($automaticStyles as $automaticStyle) {
$styleFamily = $automaticStyle->getAttributeNS($styleNs, 'family');
@@ -395,6 +396,9 @@ class Ods extends BaseReader
}
}
$automaticStyle0 = $this->readDataOnly ? null : $dom->getElementsByTagNameNS($officeNs, 'automatic-styles')->item(0);
$this->processSomeNumberFormats($automaticStyle0, $numberNs, $styleNs);
$pageSettings = new PageSettings($dom);
// Main Content
@@ -411,17 +415,7 @@ class Ods extends BaseReader
$definedNameReader = new DefinedNames($spreadsheet, $tableNs);
$columnWidths = [];
$automaticStyle0 = $this->readDataOnly ? null : $dom->getElementsByTagNameNS($officeNs, 'automatic-styles')->item(0);
$automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($numberNs, 'number-style');
foreach ($automaticStyles as $automaticStyle) {
$styleName = $automaticStyle->getAttributeNS($styleNs, 'name');
foreach ($automaticStyle->getElementsByTagNameNS($numberNs, 'number') as $numberNumber) {
$decimalPlaces = $numberNumber->getAttributeNs($numberNs, 'decimal-places');
$minIntegerDigits = (int) $numberNumber->getAttributeNs($numberNs, 'min-integer-digits');
if ($decimalPlaces === '0' && $minIntegerDigits > 1) {
$this->numberFormats[$styleName] = str_repeat('0', $minIntegerDigits);
}
}
}
$this->processSomeNumberFormats($automaticStyle0, $numberNs, $styleNs);
$automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($styleNs, 'style');
foreach ($automaticStyles as $automaticStyle) {
$styleName = $automaticStyle->getAttributeNS($styleNs, 'name');
@@ -837,7 +831,21 @@ class Ods extends BaseReader
$colRepeats = 1;
}
$styleName = $cellData->getAttributeNS($tableNs, 'style-name');
$assignedNumberFormat = $this->allStyles[$styleName]['numberFormat']['formatCode'] ?? '';
if ($styleName === '') {
if ($worksheet === null || !$worksheet->columnDimensionExists($columnID)) {
$assignedNumberFormat = '';
} else {
$colStyle = $worksheet->getColumnDimension($columnID)->getXfIndex() ?? 0;
$assignedNumberFormat = $spreadsheet
->getCellXfByIndex($colStyle)
->getNumberFormat()->getFormatCode();
if ($assignedNumberFormat === NumberFormat::FORMAT_GENERAL) {
$assignedNumberFormat = '';
}
}
} else {
$assignedNumberFormat = $this->allStyles[$styleName]['numberFormat']['formatCode'] ?? '';
}
// When a cell has number-columns-repeated, check if ANY column in the
// repeated range passes the read filter. If not, skip the entire group.
@@ -1772,4 +1780,24 @@ class Ods extends BaseReader
return $borders; // @phpstan-ignore-line
}
protected function processSomeNumberFormats(?DOMElement $automaticStyle0, string $numberNs, string $styleNs): void
{
$automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($numberNs, 'number-style');
foreach ($automaticStyles as $automaticStyle) {
$this->processNumberNumber($automaticStyle, $numberNs, $styleNs);
}
}
protected function processNumberNumber(DOMElement $automaticStyle, string $numberNs, string $styleNs): void
{
$styleName = $automaticStyle->getAttributeNS($styleNs, 'name');
foreach ($automaticStyle->getElementsByTagNameNS($numberNs, 'number') as $numberNumber) {
$decimalPlaces = $numberNumber->getAttributeNs($numberNs, 'decimal-places');
$minIntegerDigits = (int) $numberNumber->getAttributeNs($numberNs, 'min-integer-digits');
if ($decimalPlaces === '0' && $minIntegerDigits > 1) {
$this->numberFormats[$styleName] = str_repeat('0', $minIntegerDigits);
}
}
}
}
@@ -9,7 +9,7 @@ use PHPUnit\Framework\TestCase;
class Issue3721Test extends TestCase
{
public function xtestIssue2810ReadEmpty(): void
public function testIssue2810ReadEmpty(): void
{
// Problems with getHighestDataColumn
$filename = 'tests/data/Reader/Ods/issue.3721.ods';
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Reader\Ods;
use PhpOffice\PhpSpreadsheet\Reader\Ods as OdsReader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
@@ -52,4 +53,38 @@ class Leading0Test extends AbstractFunctional
$spreadsheet->disconnectWorksheets();
}
public function testConstructed0(): void
{
// style in "upper" part of styles.xml, rather than content.xml
$infile = 'tests/data/Reader/Ods/leading0.N0.ods';
$reader = new OdsReader();
$reader->setReadEmptyCells(false);
$spreadsheet = $reader->load($infile);
$sheet = $spreadsheet->getActiveSheet();
$expected = [
['1235'],
['-012'],
['-21235'],
];
self::assertSame($expected, $sheet->toArray());
$spreadsheet->disconnectWorksheets();
}
public function testConstructed2(): void
{
// style in "lower" part of styles.xml, rather than content.xml
$infile = 'tests/data/Reader/Ods/leading0.N2.ods';
$reader = new OdsReader();
$reader->setReadEmptyCells(false);
$spreadsheet = $reader->load($infile);
$sheet = $spreadsheet->getActiveSheet();
$expected = [
['0001235'],
['-000012'],
['-021235'],
];
self::assertSame($expected, $sheet->toArray());
$spreadsheet->disconnectWorksheets();
}
}
Binary file not shown.
Binary file not shown.