diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php
index 8e52713b5..3e61f2078 100644
--- a/src/PhpSpreadsheet/Reader/Ods.php
+++ b/src/PhpSpreadsheet/Reader/Ods.php
@@ -624,6 +624,9 @@ class Ods extends BaseReader
}
if ($hyperlink !== null) {
+ if ($hyperlink[0] === '#') {
+ $hyperlink = 'sheet://' . substr($hyperlink, 1);
+ }
$cell->getHyperlink()
->setUrl($hyperlink);
}
diff --git a/src/PhpSpreadsheet/Reader/Ods/Properties.php b/src/PhpSpreadsheet/Reader/Ods/Properties.php
index 8c4ccc303..33419356e 100644
--- a/src/PhpSpreadsheet/Reader/Ods/Properties.php
+++ b/src/PhpSpreadsheet/Reader/Ods/Properties.php
@@ -91,7 +91,14 @@ class Properties
break;
case 'user-defined':
- $this->setUserDefinedProperty($propertyValueAttributes, $propertyValue, $docProps);
+ $name2 = (string) ($propertyValueAttributes['name'] ?? '');
+ if ($name2 === 'Company') {
+ $docProps->setCompany($propertyValue);
+ } elseif ($name2 === 'category') {
+ $docProps->setCategory($propertyValue);
+ } else {
+ $this->setUserDefinedProperty($propertyValueAttributes, $propertyValue, $docProps);
+ }
break;
}
diff --git a/src/PhpSpreadsheet/Writer/Ods/Content.php b/src/PhpSpreadsheet/Writer/Ods/Content.php
index 311044369..f52dcfad4 100644
--- a/src/PhpSpreadsheet/Writer/Ods/Content.php
+++ b/src/PhpSpreadsheet/Writer/Ods/Content.php
@@ -250,7 +250,23 @@ class Content extends WriterPart
// break intentionally omitted
case DataType::TYPE_STRING:
$objWriter->writeAttribute('office:value-type', 'string');
- $objWriter->writeElement('text:p', $cell->getValue());
+ $url = $cell->getHyperlink()->getUrl();
+ if (empty($url)) {
+ $objWriter->writeElement('text:p', $cell->getValue());
+ } else {
+ $objWriter->startElement('text:p');
+ $objWriter->startElement('text:a');
+ $sheets = 'sheet://';
+ $lensheets = strlen($sheets);
+ if (substr($url, 0, $lensheets) === $sheets) {
+ $url = '#' . substr($url, $lensheets);
+ }
+ $objWriter->writeAttribute('xlink:href', $url);
+ $objWriter->writeAttribute('xlink:type', 'simple');
+ $objWriter->text($cell->getValue());
+ $objWriter->endElement(); // text:a
+ $objWriter->endElement(); // text:p
+ }
break;
}
diff --git a/src/PhpSpreadsheet/Writer/Ods/Meta.php b/src/PhpSpreadsheet/Writer/Ods/Meta.php
index 16f7c8b54..75023a6da 100644
--- a/src/PhpSpreadsheet/Writer/Ods/Meta.php
+++ b/src/PhpSpreadsheet/Writer/Ods/Meta.php
@@ -65,12 +65,12 @@ class Meta extends WriterPart
//
$objWriter->startElement('meta:user-defined');
$objWriter->writeAttribute('meta:name', 'Company');
- $objWriter->writeRaw($spreadsheet->getProperties()->getCompany());
+ $objWriter->writeRawData($spreadsheet->getProperties()->getCompany());
$objWriter->endElement();
$objWriter->startElement('meta:user-defined');
$objWriter->writeAttribute('meta:name', 'category');
- $objWriter->writeRaw($spreadsheet->getProperties()->getCategory());
+ $objWriter->writeRawData($spreadsheet->getProperties()->getCategory());
$objWriter->endElement();
self::writeDocPropsCustom($objWriter, $spreadsheet);
diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/HyperlinkTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/HyperlinkTest.php
new file mode 100644
index 000000000..2dc5f9cfa
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Reader/Ods/HyperlinkTest.php
@@ -0,0 +1,52 @@
+getProperties()->setCompany('gzorg');
+ $spreadsheetOld->getProperties()->setCategory('hzorg');
+ $sheet = $spreadsheetOld->getActiveSheet();
+ $sheet->getCell('A1')->setValue('Hello World');
+ $sheet->getCell('A2')->setValue('http://example.org');
+ $sheet->getCell('A2')->getHyperlink()->setUrl('http://example.org/');
+ $sheet->getCell('A3')->setValue('pagetCell('A3')->getHyperlink()->setUrl('http://example.org/page1.html');
+ $sheet2 = $spreadsheetOld->createSheet();
+ $sheet2->setTitle('TargetSheet');
+ $sheet2->setCellValue('B4', 'TargetCell');
+ $sheet2->setCellValue('B3', 'not target');
+ $sheet->getCell('A4')->setValue('go to Target');
+ $sheet->getCell('A4')->getHyperlink()->setUrl('sheet://TargetSheet!B4');
+ $spreadsheet = $this->writeAndReload($spreadsheetOld, 'Ods');
+ $spreadsheetOld->disconnectWorksheets();
+
+ $newSheet = $spreadsheet->getActiveSheet();
+ self::assertSame('gzorg', $spreadsheet->getProperties()->getCompany());
+ self::assertSame('hzorg', $spreadsheet->getProperties()->getCategory());
+ self::assertSame('http://example.org', $newSheet->getCell('A2')->getValue());
+ self::assertSame('http://example.org/', $newSheet->getCell('A2')->getHyperlink()->getUrl());
+ self::assertSame('pagetCell('A3')->getValue());
+ self::assertSame('http://example.org/page1.html', $newSheet->getCell('A3')->getHyperlink()->getUrl());
+ self::assertSame('go to Target', $newSheet->getCell('A4')->getValue());
+ self::assertSame('sheet://TargetSheet!B4', $newSheet->getCell('A4')->getHyperlink()->getUrl());
+
+ // Verify that http links are unchanged,
+ // but internal sheet link has changed.
+ $writer = new Ods($spreadsheet);
+ $content = $writer->getWriterPartContent()->write();
+ self::assertStringContainsString('xlink:href="http://example.org/"', $content);
+ self::assertStringContainsString('xlink:href="http://example.org/page1.html"', $content);
+ self::assertStringContainsString('xlink:href="#TargetSheet!B4"', $content);
+ self::assertStringNotContainsString('sheet:', $content);
+
+ $spreadsheet->disconnectWorksheets();
+ }
+}