Ods Comments With Newlines

Fix #4081. Ods Reader was not reading entire contents of comment. On further inspection, Ods Writer also was not handling comments completely correctly. Ods comments are recorded as `text:p` children of `office:annotation` elements. A newline is inserted between successive `text:p` elements. The `text:p` element itself can have as descendants (at least):
- raw text
- `text:span` elements
- `text:line-break` elements, which also causes the insertion of a newline

Ods Writer is changed to use a single `text:p` with multiple span/linebreak elements. Ods Reader is changed to process in their entirety either that form, or multiple `text:p` elements. Styling of the individual elements of the comment is permitted in Ods. That has not been supported till now by PhpSpreadsheet, and this PR will not address that situation - Ods Reader hast little style support, and this would hardly be the most urgent case where it is missing.
This commit is contained in:
oleibman
2024-07-01 14:52:23 -07:00
parent 318a82e0f9
commit 8557ccb72a
4 changed files with 77 additions and 8 deletions
+20 -7
View File
@@ -436,14 +436,25 @@ class Ods extends BaseReader
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;
if ($textNode->length > 0 && $textNode->item(0) !== null) {
$text = $this->scanElementForText($textNode->item(0));
$spreadsheet->getActiveSheet()
->getComment($columnID . $rowID)
->setText($this->parseRichText($text));
// ->setAuthor( $author )
$spreadsheet->getActiveSheet()
->getComment($columnID . $rowID)
->getText()
->createText($this->parseRichText($text));
}
}
}
@@ -731,6 +742,8 @@ class Ods extends BaseReader
/** @var DOMNode $child */
if ($child->nodeType == XML_TEXT_NODE) {
$str .= $child->nodeValue;
} elseif ($child->nodeType == XML_ELEMENT_NODE && $child->nodeName == 'text:line-break') {
$str .= "\n";
} elseif ($child->nodeType == XML_ELEMENT_NODE && $child->nodeName == 'text:s') {
// It's a space
+16 -1
View File
@@ -24,7 +24,22 @@ class Comment
$objWriter->writeAttribute('svg:x', $comment->getMarginLeft());
$objWriter->writeAttribute('svg:y', $comment->getMarginTop());
$objWriter->writeElement('dc:creator', $comment->getAuthor());
$objWriter->writeElement('text:p', $comment->getText()->getPlainText());
$objWriter->startElement('text:p');
$text = $comment->getText()->getPlainText();
$textElements = explode("\n", $text);
$newLineOwed = false;
foreach ($textElements as $textSegment) {
if ($newLineOwed) {
$objWriter->writeElement('text:line-break');
}
$newLineOwed = true;
if ($textSegment !== '') {
$objWriter->writeElement('text:span', $textSegment);
}
}
$objWriter->endElement(); // text:p
$objWriter->endElement();
}
}
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Reader\Ods;
use PhpOffice\PhpSpreadsheet\Reader\Ods;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class MultiLineCommentTest extends AbstractFunctional
{
public function testMultipleParagraphs(): void
{
$filename = 'tests/data/Reader/Ods/issue.4081.ods';
$reader = new Ods();
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertSame("First line.\n\nSecond line.", $sheet->getComment('A1')->getText()->getPlainText());
$spreadsheet->disconnectWorksheets();
}
public function testOneParagraphMultipleSpans(): void
{
$spreadsheetOld = new Spreadsheet();
$sheetOld = $spreadsheetOld->getActiveSheet();
$sheetOld->getCell('A1')->setValue('Hello');
$text = $sheetOld->getComment('A1')->getText();
$text->createText('First');
$text->createText(' line.');
$text->createText("\n");
$text->createText("\n");
$text->createText("Second line.\nThird line.");
$spreadsheet = $this->writeAndReload($spreadsheetOld, 'Ods');
$spreadsheetOld->disconnectWorksheets();
$sheet = $spreadsheet->getActiveSheet();
self::assertSame("First line.\n\nSecond line.\nThird line.", $sheet->getComment('A1')->getText()->getPlainText());
$spreadsheet->disconnectWorksheets();
}
}
Binary file not shown.