From 1d86675e048862c34172d76db409e7ad10b73a84 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 3 Jul 2024 19:56:38 -0700 Subject: [PATCH 01/14] Ods Xml Reader and Whitespace Text Nodes Fix #804, opened in Dec. 2018, and closed as stale in Feb. 2019, and which I have re-opened to be closed properly by this PR. Better late than never, I suppose. A third party generated an ODS spreadsheet which PhpSpreadsheet could not read. By way of explanation, the xml in the file contained lots of whitespace between tags, which is wonderful for those humans among us who have to analyze it; but PhpSpreadsheet was not prepared for it. It is now. --- src/PhpSpreadsheet/Reader/Ods.php | 6 ++- .../Reader/Ods/Issue804Test.php | 38 ++++++++++++++++++ tests/data/Reader/Ods/issue.804.ods | Bin 0 -> 4979 bytes 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Ods/Issue804Test.php create mode 100644 tests/data/Reader/Ods/issue.804.ods diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index ceb345dc3..746210ab3 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -6,6 +6,7 @@ use DOMAttr; use DOMDocument; use DOMElement; use DOMNode; +use DOMText; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Helper\Dimension as HelperDimension; @@ -403,8 +404,11 @@ class Ods extends BaseReader } $columnID = 'A'; - /** @var DOMElement $cellData */ + /** @var DOMElement|DOMText $cellData */ foreach ($childNode->childNodes as $cellData) { + if ($cellData instanceof DOMText) { + continue; // should just be whitespace + } if ($this->getReadFilter() !== null) { if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/Issue804Test.php b/tests/PhpSpreadsheetTests/Reader/Ods/Issue804Test.php new file mode 100644 index 000000000..afb33dabe --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/Issue804Test.php @@ -0,0 +1,38 @@ + + + Name', $data); + } + } + + public function testIssue2810(): void + { + // Whitespace between Xml nodes + $filename = 'tests/data/Reader/Ods/issue.804.ods'; + $reader = new Ods(); + $spreadsheet = $reader->load($filename); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame('Straße', $sheet->getCell('G1')->getValue()); + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/data/Reader/Ods/issue.804.ods b/tests/data/Reader/Ods/issue.804.ods new file mode 100644 index 0000000000000000000000000000000000000000..b42de4cf635d248d117abde3ef3f084c93e3b9d6 GIT binary patch literal 4979 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 id!LYZb(AEAgzr8tLoZU1i~s-@(u Date: Thu, 4 Jul 2024 20:06:17 -0700 Subject: [PATCH 02/14] Documentation Updates Mostly in response to issue #3961, which noted some discrepancies, both positive and negative, between documentation and reality concerning ODS support. --- docs/index.md | 3 ++ docs/references/features-cross-reference.md | 35 +++++++++++---------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/docs/index.md b/docs/index.md index 9505181b7..d577d8982 100644 --- a/docs/index.md +++ b/docs/index.md @@ -20,6 +20,9 @@ allow you to read and write various spreadsheet file formats such as Excel and L |CSV | ✓ | ✓ | |PDF (using either the TCPDF, Dompdf or mPDF libraries, which need to be installed separately)| | ✓ | +Note - reading or writing certain aspects of a spreadsheet may not be supported in all formats. For more details, please consult +[Features Cross-reference](./references/features-cross-reference.md). + # Getting started ## Software requirements diff --git a/docs/references/features-cross-reference.md b/docs/references/features-cross-reference.md index 37668ba82..f116be511 100644 --- a/docs/references/features-cross-reference.md +++ b/docs/references/features-cross-reference.md @@ -28,7 +28,7 @@ ✔ ✔ ● - ● + ● 6 ✔ N/A N/A @@ -389,7 +389,7 @@ Conditional Formatting - ● + ✔ ✔ ✖ ✖ @@ -414,7 +414,7 @@ ✔ ✔ ✔ - ✖ + ✔ ✔ N/A N/A @@ -502,7 +502,7 @@ ✔ ✔ ✔ - ✔ + ● ✔ N/A ✔ @@ -797,13 +797,13 @@ Alignment ✖ 3 - ✖ + ✔ ✖ ✖ ✖ N/A ✖ - ✖ + ✔ Background Image @@ -929,7 +929,7 @@ Macros ✖ - ✔ + ● 5 ✖ ✖ ✖ @@ -940,7 +940,7 @@ Form Controls ✖ - ✖ + ● 4 ✖ ✖ ✖ @@ -1001,6 +1001,9 @@ 1. Only text contents 2. Only BIFF8 files support Rich Text. Prior to that, comments could only be plain text 3. Only BIFF8 files support alignment and rotation. Prior to that, comments could only be unformatted text +4. Xlsx forms and controls can be read and written but not otherwise manipulated +5. Xlsx macros can be read and written; their values can be retrieved and changed, but only in a binary form which is unlikely to be useful +6. There is very limited support for reading styles from an Ods spreadsheet. Writing styles has better support, although Number Format is incomplete. ## Writers @@ -1184,7 +1187,7 @@ Row Height/Column Width ✔ ✔ - ✖ + ✔ N/A ✔ ✔ @@ -1256,7 +1259,7 @@ Number Format Mask ✔ ✔ - ✔ + ● N/A ✔ ✔ @@ -1472,10 +1475,10 @@ Merged Cells ✔ ✔ - ✖ + ✔ N/A ✔ - ✖ + ✔ Cell Comments @@ -1606,7 +1609,7 @@ Macros ✖ - ✔ + ● 5 ✖ N/A ✖ @@ -1615,7 +1618,7 @@ Form Controls ✖ - ✖ + ● 4 ✖ N/A ✖ @@ -1803,8 +1806,8 @@ Macros - $spreadsheet->getMacrosCode(); - $spreadsheet->setMacrosCode(); + $spreadsheet->getMacrosCode();5 + $spreadsheet->setMacrosCode();5 Security From 2897c4de33d7107b2038cd572f27ac96a2a29b9e Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 4 Jul 2024 20:18:25 -0700 Subject: [PATCH 03/14] Missed One Doc Change --- docs/references/features-cross-reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/references/features-cross-reference.md b/docs/references/features-cross-reference.md index f116be511..23dfbb333 100644 --- a/docs/references/features-cross-reference.md +++ b/docs/references/features-cross-reference.md @@ -1501,10 +1501,10 @@ Alignment ✖ - ✖ + ✔ ✖ N/A - ✖ + ✔ N/A From 070ceef5d0bb0557dd91fd795eb34457117d189b Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Fri, 5 Jul 2024 20:57:43 -0700 Subject: [PATCH 04/14] Changes to INDEX Function Fix #64 (really!), closed as stale in December 2017, another in our "better late than never" series. Excel's INDEX function doesn't really behave quite as described. If a single row is used as an argument, either in literal form `{item1, item2, item3}` or expressed as a range `A1:A6`, INDEX is happy to evaluate the array as if each entry were a row rather than a single item. PhpSpreadsheet is changed to do likewise. INDEX also returned `#REF!` when it would normally return an array (which would often be reduced to its leftmost topmost entry later). This code is deleted, invalidating one existing test, and INDEX will now operate like other functions which can return arrays. --- .../Calculation/LookupRef/Matrix.php | 15 ++++++--- .../LookupRef/IndexOnSpreadsheetTest.php | 33 +++++++++++++++++++ .../LookupRef/INDEXonSpreadsheet.php | 2 +- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php index d578854de..228b46448 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php @@ -81,7 +81,6 @@ class Matrix } $rowNum = $rowNum ?? 0; - $originalColumnNum = $columnNum; $columnNum = $columnNum ?? 0; try { @@ -91,6 +90,17 @@ class Matrix return $e->getMessage(); } + if (is_array($matrix) && count($matrix) === 1 && $rowNum > 1) { + $matrixKey = array_keys($matrix)[0]; + if (is_array($matrix[$matrixKey])) { + $tempMatrix = []; + foreach ($matrix[$matrixKey] as $key => $value) { + $tempMatrix[$key] = [$value]; + } + $matrix = $tempMatrix; + } + } + if (!is_array($matrix) || ($rowNum > count($matrix))) { return ExcelError::REF(); } @@ -101,9 +111,6 @@ class Matrix if ($columnNum > count($columnKeys)) { return ExcelError::REF(); } - if ($originalColumnNum === null && 1 < count($columnKeys)) { - return ExcelError::REF(); - } if ($columnNum === 0) { return self::extractRowValue($matrix, $rowKeys, $rowNum); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexOnSpreadsheetTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexOnSpreadsheetTest.php index e893fc7f3..3f508405a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexOnSpreadsheetTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexOnSpreadsheetTest.php @@ -34,4 +34,37 @@ class IndexOnSpreadsheetTest extends AllSetupTeardown { return require 'tests/data/Calculation/LookupRef/INDEXonSpreadsheet.php'; } + + /** + * @dataProvider providerIndexLiteralArrays + */ + public function testLiteralArrays(mixed $expectedResult, string $indexArgs): void + { + $sheet = $this->getSheet(); + $sheet->getCell('A10')->setValue(10); + $sheet->getCell('B10')->setValue(11); + $sheet->getCell('C10')->setValue(12); + $sheet->getCell('D10')->setValue(13); + $sheet->getCell('X10')->setValue(10); + $sheet->getCell('X11')->setValue(11); + $sheet->getCell('X12')->setValue(12); + $sheet->getCell('X13')->setValue(13); + $sheet->getCell('A1')->setValue("=INDEX($indexArgs)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public static function providerIndexLiteralArrays(): array + { + return [ + 'issue 64' => ['Fourth', '{"First","Second","Third","Fourth","Fifth","Sixth","Seventh"}, 4'], + 'issue 64 selecting first "row"' => ['First', '{"First","Second","Third","Fourth","Fifth","Sixth","Seventh"}, 1'], + 'array result condensed to single value' => [40, '{10,11;20,21;30,31;40,41;50,51;60,61},4'], + 'both row and column' => [41, '{10,11;20,21;30,31;40,41;50,51;60,61},4,2'], + '1*1 array' => ['first', '{"first"},1'], + 'array expressed in rows' => [20, '{10;20;30;40},2'], + 'spreadsheet single row' => [11, 'A10:D10,2'], + 'spreadsheet single column' => [13, 'X10:X13,4'], + ]; + } } diff --git a/tests/data/Calculation/LookupRef/INDEXonSpreadsheet.php b/tests/data/Calculation/LookupRef/INDEXonSpreadsheet.php index 76f6ddd46..b2202704d 100644 --- a/tests/data/Calculation/LookupRef/INDEXonSpreadsheet.php +++ b/tests/data/Calculation/LookupRef/INDEXonSpreadsheet.php @@ -82,7 +82,7 @@ return [ 2, ], 'Column number omitted from 2-column matrix' => [ - '#REF!', // Expected + 'abc', // Expected [ ['abc', 'def'], ['xyz', 'tuv'], From 10123c441b3d963ba18ffc5d0f42b20b912ba61e Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sat, 6 Jul 2024 19:58:19 -0700 Subject: [PATCH 05/14] Html Writer Minor Fixes While researching issue #1551, I came across some minor problems. When a spreadsheet does not have a title, which is often the case for spreadsheets created with Excel (note that this is not the case for spreadsheets created with PhpSpreadsheet), if you try to save it as Html, it throws an exception. It will now use the sheet title of the active sheet as a title in this case. When writing an Html spreadsheet using `useInlineCss(true)`, gridlines are not handled properly. This is addressed by adding `class=gridlines gridlinesp` to the cell's `td` tag, and by suppressing any border attributes which would be styled as `none #000000`. It would be unusual to turn off gridlines for specific cells, but that can still be accomplished by using `Border::BORDER_NONE` in conjunction with any color other than `#000000` - see new test `testHideSomeGridlines`. --- src/PhpSpreadsheet/Writer/Html.php | 16 ++++- .../Writer/Html/Issue3678Test.php | 5 +- .../Writer/Html/NoTitleTest.php | 61 +++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index 457af6612..37a9c8994 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -355,7 +355,11 @@ class Html extends BaseWriter $html .= ' ' . PHP_EOL; $html .= ' ' . PHP_EOL; $html .= ' ' . PHP_EOL; - $html .= ' ' . htmlspecialchars($properties->getTitle(), Settings::htmlEntityFlags()) . '' . PHP_EOL; + $title = $properties->getTitle(); + if ($title === '') { + $title = $this->spreadsheet->getActiveSheet()->getTitle(); + } + $html .= ' ' . htmlspecialchars($title, Settings::htmlEntityFlags()) . '' . PHP_EOL; $html .= self::generateMeta($properties->getCreator(), 'author'); $html .= self::generateMeta($properties->getTitle(), 'title'); $html .= self::generateMeta($properties->getDescription(), 'description'); @@ -1462,11 +1466,21 @@ class Html extends BaseWriter $xcssClass['height'] = $height; } //** end of redundant code ** + if ($this->useInlineCss) { + foreach (['border-top', 'border-bottom', 'border-right', 'border-left'] as $borderType) { + if (($xcssClass[$borderType] ?? '') === 'none #000000') { + unset($xcssClass[$borderType]); + } + } + } if ($htmlx) { $xcssClass['position'] = 'relative'; } $html .= ' style="' . $this->assembleCSS($xcssClass) . '"'; + if ($this->useInlineCss) { + $html .= ' class="gridlines gridlinesp"'; + } } $html = $this->generateRowSpans($html, $rowSpan, $colSpan); diff --git a/tests/PhpSpreadsheetTests/Writer/Html/Issue3678Test.php b/tests/PhpSpreadsheetTests/Writer/Html/Issue3678Test.php index cabcaca8f..e4f292c2d 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/Issue3678Test.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/Issue3678Test.php @@ -24,7 +24,8 @@ class Issue3678Test extends TestCase ]; $sheet->getStyle('A1')->applyFromArray($styleArray); $style1 = "vertical-align:bottom; border-bottom:none #000000; border-top:none #000000; border-left:none #000000; border-right:none #000000; color:#000000; font-family:'Calibri'; font-size:11pt; background-color:#FFFF00"; - $style2 = $style1 . '; text-align:right; width:42pt'; + $style2 = "vertical-align:bottom; color:#000000; font-family:'Calibri'; font-size:11pt; background-color:#FFFF00"; + $style2 .= '; text-align:right; width:42pt'; $writer = new Html($spreadsheet); $html = $writer->generateHtmlAll(); self::assertStringContainsString('td.style1, th.style1 { ' . $style1 . ' }', $html); @@ -33,7 +34,7 @@ class Issue3678Test extends TestCase self::assertStringContainsString('.n { text-align:right }', $html); $writer->setUseInlineCss(true); $html = $writer->generateHtmlAll(); - self::assertStringContainsString('1', $html); + self::assertStringContainsString('1', $html); $spreadsheet->disconnectWorksheets(); } } diff --git a/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php b/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php new file mode 100644 index 000000000..264e88b4e --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php @@ -0,0 +1,61 @@ +load($file); + self::assertSame('', $spreadsheet->getProperties()->getTitle()); + + $writer = new Html($spreadsheet); + $writer->setUseInlineCss(true); + $html = $writer->generateHTMLAll(); + self::assertStringContainsString('Sheet1', $html); + self::assertStringContainsString('C1', $html); + $writer->setUseInlineCss(false); + $html = $writer->generateHTMLAll(); + self::assertStringContainsString('C1', $html); + $spreadsheet->disconnectWorksheets(); + } + + public function testHideSomeGridlines(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->fromArray( + [ + [1, 2, 3, 4, 5, 6], + [7, 8, 9, 10, 11, 12], + [17, 18, 19, 20, 21, 22], + [27, 28, 29, 30, 31, 32], + [37, 38, 39, 40, 41, 42], + ]); + $sheet->getStyle('B2:D4')->getBorders()->applyFromArray( + [ + 'allBorders' => [ + 'borderStyle' => Border::BORDER_NONE, + 'color' => ['rgb' => '808080'], + ], + ], + ); + + $writer = new Html($spreadsheet); + $writer->setUseInlineCss(true); + $html = $writer->generateHTMLAll(); + self::assertStringContainsString('7', $html); + self::assertStringContainsString('19', $html); + $spreadsheet->disconnectWorksheets(); + } +} From 3fee2c02e319140d199c8d4e5d3f7ab834602b5f Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sat, 6 Jul 2024 20:15:19 -0700 Subject: [PATCH 06/14] Wrong Case in File Name --- tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php b/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php index 264e88b4e..cedfe8dd2 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php @@ -14,7 +14,7 @@ class NoTitleTest extends TestCase { public function testNoTitle(): void { - $file = 'tests/data/Reader/Xlsx/blankcell.xlsx'; + $file = 'tests/data/Reader/XLSX/blankcell.xlsx'; $reader = new XlsxReader(); $spreadsheet = $reader->load($file); self::assertSame('', $spreadsheet->getProperties()->getTitle()); From 7e3afabba833fcea44af37d7dc5a0ab15e6169ba Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sat, 6 Jul 2024 20:24:43 -0700 Subject: [PATCH 07/14] Formatting errors --- tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php b/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php index cedfe8dd2..7faf8a6ad 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/NoTitleTest.php @@ -41,7 +41,8 @@ class NoTitleTest extends TestCase [17, 18, 19, 20, 21, 22], [27, 28, 29, 30, 31, 32], [37, 38, 39, 40, 41, 42], - ]); + ] + ); $sheet->getStyle('B2:D4')->getBorders()->applyFromArray( [ 'allBorders' => [ From f6823c79e825518afbc6aa883ff5e22630865444 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sat, 6 Jul 2024 20:26:15 -0700 Subject: [PATCH 08/14] More Doc Updates --- docs/references/features-cross-reference.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/references/features-cross-reference.md b/docs/references/features-cross-reference.md index 23dfbb333..746357894 100644 --- a/docs/references/features-cross-reference.md +++ b/docs/references/features-cross-reference.md @@ -495,7 +495,7 @@ ✔ N/A ● - ● + ● 7 Number Format Mask @@ -517,7 +517,7 @@ ✔ N/A ✖ - ● + ● 7 Horizontal @@ -583,7 +583,7 @@ ✔ N/A ✔ - ✔ + ● 7 Patterned @@ -605,7 +605,7 @@ ✔ N/A ✔ - ✔ + ● 7 Font Face @@ -704,7 +704,7 @@ ✔ N/A ● - ✔ + ● 7 Line Style @@ -1004,6 +1004,7 @@ 4. Xlsx forms and controls can be read and written but not otherwise manipulated 5. Xlsx macros can be read and written; their values can be retrieved and changed, but only in a binary form which is unlikely to be useful 6. There is very limited support for reading styles from an Ods spreadsheet. Writing styles has better support, although Number Format is incomplete. +7. In most cases, Html reader processes only inline styles; styles provided by Css classes may be ignored. ## Writers From f6f155263c7cfb0feafcb71d1a7af3526548703d Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 10 Jul 2024 20:13:50 -0700 Subject: [PATCH 09/14] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b595933..760df33ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Problem rendering line chart with missing plot label. [PR #4074](https://github.com/PHPOffice/PhpSpreadsheet/pull/4074) - More RTL in Xlsx/Html Comments [Issue #4004](https://github.com/PHPOffice/PhpSpreadsheet/issues/4004) [PR #4065](https://github.com/PHPOffice/PhpSpreadsheet/pull/4065) - Empty String in sharedStrings. [Issue #4063](https://github.com/PHPOffice/PhpSpreadsheet/issues/4063) [PR #4064](https://github.com/PHPOffice/PhpSpreadsheet/pull/4064) +- Ods Xml Reader and Whitespace Text Nodes. [Issue #804](https://github.com/PHPOffice/PhpSpreadsheet/issues/804) [PR #4087](https://github.com/PHPOffice/PhpSpreadsheet/pull/4087) ## 2024-05-11 - 2.1.0 From 18e3c00e405d84e09438f180150f9759f82df693 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 11 Jul 2024 19:48:12 -0700 Subject: [PATCH 10/14] Performance Improvements for Csv Reader Fix #460. Another in the "better late than never" series, closed as stale in June 2018. Ods Writer and Ods Reader handle booleans differently; what is worse, neither of them do it correctly. They will now match the behavior of LibreOffice. Reporter said that part of the xml would vary depending on locale; I believe that part is never actually used, but I do emulate that behavior. --- src/PhpSpreadsheet/Reader/Ods.php | 2 +- src/PhpSpreadsheet/Writer/Ods/Content.php | 5 +- .../CalculationFunctionListTest.php | 6 -- .../Calculation/CalculationTest.php | 6 -- .../Reader/Ods/BooleanDataTest.php | 83 +++++++++++++++++++ tests/data/Writer/Ods/content-with-data.xml | 8 +- 6 files changed, 91 insertions(+), 19 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Ods/BooleanDataTest.php diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index ceb345dc3..e3d86e624 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -492,7 +492,7 @@ class Ods extends BaseReader break; case 'boolean': $type = DataType::TYPE_BOOL; - $dataValue = ($allCellDataText == 'TRUE') ? true : false; + $dataValue = ($cellData->getAttributeNS($officeNs, 'boolean-value') === 'true') ? true : false; break; case 'percentage': diff --git a/src/PhpSpreadsheet/Writer/Ods/Content.php b/src/PhpSpreadsheet/Writer/Ods/Content.php index 7b052bbcc..7ffcd46b6 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Content.php +++ b/src/PhpSpreadsheet/Writer/Ods/Content.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Ods; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; @@ -209,8 +210,8 @@ class Content extends WriterPart switch ($cell->getDataType()) { case DataType::TYPE_BOOL: $objWriter->writeAttribute('office:value-type', 'boolean'); - $objWriter->writeAttribute('office:value', $cell->getValueString()); - $objWriter->writeElement('text:p', $cell->getValueString()); + $objWriter->writeAttribute('office:boolean-value', $cell->getValue() ? 'true' : 'false'); + $objWriter->writeElement('text:p', Calculation::getInstance()->getLocaleBoolean($cell->getValue() ? 'TRUE' : 'FALSE')); break; case DataType::TYPE_ERROR: diff --git a/tests/PhpSpreadsheetTests/Calculation/CalculationFunctionListTest.php b/tests/PhpSpreadsheetTests/Calculation/CalculationFunctionListTest.php index f961c7ac7..978162667 100644 --- a/tests/PhpSpreadsheetTests/Calculation/CalculationFunctionListTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/CalculationFunctionListTest.php @@ -13,21 +13,15 @@ class CalculationFunctionListTest extends TestCase { private string $compatibilityMode; - private string $locale; - protected function setUp(): void { $this->compatibilityMode = Functions::getCompatibilityMode(); - $calculation = Calculation::getInstance(); - $this->locale = $calculation->getLocale(); Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); } protected function tearDown(): void { Functions::setCompatibilityMode($this->compatibilityMode); - $calculation = Calculation::getInstance(); - $calculation->setLocale($this->locale); } /** diff --git a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php index 79685d267..797b0bfd7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php @@ -15,21 +15,15 @@ class CalculationTest extends TestCase { private string $compatibilityMode; - private string $locale; - protected function setUp(): void { $this->compatibilityMode = Functions::getCompatibilityMode(); - $calculation = Calculation::getInstance(); - $this->locale = $calculation->getLocale(); Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); } protected function tearDown(): void { Functions::setCompatibilityMode($this->compatibilityMode); - $calculation = Calculation::getInstance(); - $calculation->setLocale($this->locale); } /** diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/BooleanDataTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/BooleanDataTest.php new file mode 100644 index 000000000..28efec197 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/BooleanDataTest.php @@ -0,0 +1,83 @@ +locale = $calculation->getLocale(); + } + + protected function tearDown(): void + { + $calculation = Calculation::getInstance(); + $calculation->setLocale($this->locale); + if ($this->tempfile !== '') { + unlink($this->tempfile); + $this->tempfile = ''; + } + } + + public function testBooleanData(): void + { + $spreadsheetOld = new Spreadsheet(); + $sheetOld = $spreadsheetOld->getActiveSheet(); + $sheetOld->getCell('A1')->setValue(true); + $sheetOld->getCell('A2')->setValue(false); + $writer = new OdsWriter($spreadsheetOld); + $this->tempfile = File::temporaryFileName(); + $writer->save($this->tempfile); + $spreadsheetOld->disconnectWorksheets(); + $reader = new OdsReader(); + $spreadsheet = $reader->load($this->tempfile); + $sheet = $spreadsheet->getActiveSheet(); + self::assertTrue($sheet->getCell('A1')->getValue()); + self::assertFalse($sheet->getCell('A2')->getValue()); + $spreadsheet->disconnectWorksheets(); + $zipFile = 'zip://' . $this->tempfile . '#content.xml'; + $contents = (string) file_get_contents($zipFile); + self::assertStringContainsString('TRUE', $contents); + self::assertStringContainsString('FALSE', $contents); + } + + public function testBooleanDataGerman(): void + { + $calculation = Calculation::getInstance(); + $calculation->setLocale('de'); + $spreadsheetOld = new Spreadsheet(); + $sheetOld = $spreadsheetOld->getActiveSheet(); + $sheetOld->getCell('A1')->setValue(true); + $sheetOld->getCell('A2')->setValue(false); + $writer = new OdsWriter($spreadsheetOld); + $this->tempfile = File::temporaryFileName(); + $writer->save($this->tempfile); + $spreadsheetOld->disconnectWorksheets(); + $reader = new OdsReader(); + $spreadsheet = $reader->load($this->tempfile); + $sheet = $spreadsheet->getActiveSheet(); + self::assertTrue($sheet->getCell('A1')->getValue()); + self::assertFalse($sheet->getCell('A2')->getValue()); + $spreadsheet->disconnectWorksheets(); + $zipFile = 'zip://' . $this->tempfile . '#content.xml'; + $contents = (string) file_get_contents($zipFile); + self::assertStringContainsString('WAHR', $contents); + self::assertStringContainsString('FALSCH', $contents); + self::assertStringNotContainsString('TRUE', $contents); + self::assertStringNotContainsString('FALSE', $contents); + } +} diff --git a/tests/data/Writer/Ods/content-with-data.xml b/tests/data/Writer/Ods/content-with-data.xml index 12140fa92..bb115583c 100644 --- a/tests/data/Writer/Ods/content-with-data.xml +++ b/tests/data/Writer/Ods/content-with-data.xml @@ -95,11 +95,11 @@ - - 1 + + TRUE - - + + FALSE 1 1 From 6ab27d2931c3a996e481cb7a226b56a72c670301 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 11 Jul 2024 20:05:16 -0700 Subject: [PATCH 11/14] Xlsx Writer Rich Text and TYPE_STRING Fix #476. Another in the "better late than never" series, closed as stale in June 2018. Xlsx Writer expects cells containing RichText to have DataType `TYPE_INLINE`; but the spreadsheet associated with the issue has the cell defined as `TYPE_STRING`. Change Writer to handle RichText TYPE_STRING appropriately. --- src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 2 +- .../Writer/Xlsx/Issue476Test.php | 30 ++++++++++++++++++ tests/data/Writer/XLSX/issue.476.xlsx | Bin 0 -> 9028 bytes 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/PhpSpreadsheetTests/Writer/Xlsx/Issue476Test.php create mode 100644 tests/data/Writer/XLSX/issue.476.xlsx diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index a1940f329..bd6eec367 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -1528,7 +1528,7 @@ class Worksheet extends WriterPart break; case 's': // String - $this->writeCellString($objWriter, $mappedType, $cellValueString, $flippedStringTable); + $this->writeCellString($objWriter, $mappedType, ($cellValue instanceof RichText) ? $cellValue : $cellValueString, $flippedStringTable); break; case 'f': // Formula diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue476Test.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue476Test.php new file mode 100644 index 000000000..513fe7940 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue476Test.php @@ -0,0 +1,30 @@ +load('tests/data/Writer/XLSX/issue.476.xlsx'); + + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); + $spreadsheet->disconnectWorksheets(); + + $sheet = $reloadedSpreadsheet->getActiveSheet(); + $richText = $sheet->getCell('A1')->getValue(); + self::assertInstanceOf(RichText::class, $richText); + $plainText = $richText->getPlainText(); + self::assertSame("Art. 1A of the Geneva Refugee Convention and Protocol or other international or national instruments.\n", $plainText); + + $reloadedSpreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/data/Writer/XLSX/issue.476.xlsx b/tests/data/Writer/XLSX/issue.476.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f76f2d227f50eb47cd663917d5c6b6b226b040cc GIT binary patch literal 9028 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 literal 0 HcmV?d00001 From 9652ffe73a0f67c71c59c3b96e8fec20a6c86451 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 11 Jul 2024 20:38:22 -0700 Subject: [PATCH 12/14] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b595933..1e518a0ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Problem rendering line chart with missing plot label. [PR #4074](https://github.com/PHPOffice/PhpSpreadsheet/pull/4074) - More RTL in Xlsx/Html Comments [Issue #4004](https://github.com/PHPOffice/PhpSpreadsheet/issues/4004) [PR #4065](https://github.com/PHPOffice/PhpSpreadsheet/pull/4065) - Empty String in sharedStrings. [Issue #4063](https://github.com/PHPOffice/PhpSpreadsheet/issues/4063) [PR #4064](https://github.com/PHPOffice/PhpSpreadsheet/pull/4064) +- Changes to INDEX function. [Issue #64](https://github.com/PHPOffice/PhpSpreadsheet/issues/64) [PR #4088](https://github.com/PHPOffice/PhpSpreadsheet/pull/4088) +- Ods Reader and Whitespace Text Nodes. [Issue #804](https://github.com/PHPOffice/PhpSpreadsheet/issues/804) [PR #4087](https://github.com/PHPOffice/PhpSpreadsheet/pull/4087) ## 2024-05-11 - 2.1.0 From ed677fe6e9d2a9bb95cbad473f61cbc265835f3f Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Fri, 12 Jul 2024 09:28:23 -0700 Subject: [PATCH 13/14] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b595933..11bd48dd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Problem rendering line chart with missing plot label. [PR #4074](https://github.com/PHPOffice/PhpSpreadsheet/pull/4074) - More RTL in Xlsx/Html Comments [Issue #4004](https://github.com/PHPOffice/PhpSpreadsheet/issues/4004) [PR #4065](https://github.com/PHPOffice/PhpSpreadsheet/pull/4065) - Empty String in sharedStrings. [Issue #4063](https://github.com/PHPOffice/PhpSpreadsheet/issues/4063) [PR #4064](https://github.com/PHPOffice/PhpSpreadsheet/pull/4064) +- Html Writer Minor Fixes. [PR #4089](https://github.com/PHPOffice/PhpSpreadsheet/pull/4089) ## 2024-05-11 - 2.1.0 From d76481f668b84a78115dc17bc7128f3cc6126ba6 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:41:14 -0700 Subject: [PATCH 14/14] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b595933..abdee5b3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Problem rendering line chart with missing plot label. [PR #4074](https://github.com/PHPOffice/PhpSpreadsheet/pull/4074) - More RTL in Xlsx/Html Comments [Issue #4004](https://github.com/PHPOffice/PhpSpreadsheet/issues/4004) [PR #4065](https://github.com/PHPOffice/PhpSpreadsheet/pull/4065) - Empty String in sharedStrings. [Issue #4063](https://github.com/PHPOffice/PhpSpreadsheet/issues/4063) [PR #4064](https://github.com/PHPOffice/PhpSpreadsheet/pull/4064) +- Xlsx Writer RichText and TYPE_STRING. [Issue #476](https://github.com/PHPOffice/PhpSpreadsheet/issues/476) [PR #4094](https://github.com/PHPOffice/PhpSpreadsheet/pull/4094) +- Ods boolean data. [Issue #460](https://github.com/PHPOffice/PhpSpreadsheet/issues/460) [PR #4093](https://github.com/PHPOffice/PhpSpreadsheet/pull/4093) ## 2024-05-11 - 2.1.0