Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specify data type in html tags using attributes #3445

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions src/PhpSpreadsheet/Reader/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use DOMNode;
use DOMText;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension;
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
Expand Down Expand Up @@ -283,15 +284,34 @@ protected function releaseTableStartColumn(): string
* @param int|string $row
* @param mixed $cellContent
*/
protected function flushCell(Worksheet $sheet, $column, $row, &$cellContent): void
protected function flushCell(Worksheet $sheet, $column, $row, &$cellContent, array $attributeArray): void
{
if (is_string($cellContent)) {
// Simple String content
if (trim($cellContent) > '') {
// Only actually write it if there's content in the string
// Write to worksheet to be done here...
// ... we return the cell so we can mess about with styles more easily
$sheet->setCellValue($column . $row, $cellContent);
// ... we return the cell, so we can mess about with styles more easily

// Set cell value explicitly if there is data-type attribute
if (isset($attributeArray['data-type'])) {
$datatype = $attributeArray['data-type'];
if ($datatype == DataType::TYPE_STRING || $datatype == DataType::TYPE_STRING2) {
PouriaSeyfi marked this conversation as resolved.
Show resolved Hide resolved
if (substr($cellContent, 0, 1) === '=' || is_numeric($cellContent)) {
PouriaSeyfi marked this conversation as resolved.
Show resolved Hide resolved
$sheet->getCell($column . $row)
->getStyle()
->setQuotePrefix(true);
}
}
//catching the Exception and ignoring the invalid data types
try {
$sheet->setCellValueExplicit($column . $row, $cellContent, $attributeArray['data-type']);
} catch (\PhpOffice\PhpSpreadsheet\Exception $exception) {
$sheet->setCellValue($column . $row, $cellContent);
}
} else {
$sheet->setCellValue($column . $row, $cellContent);
}
$this->dataArray[$row][$column] = $cellContent;
}
} else {
Expand Down Expand Up @@ -355,7 +375,7 @@ private function processDomElementSpanEtc(Worksheet $sheet, int &$row, string &$
private function processDomElementHr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
{
if ($child->nodeName === 'hr') {
$this->flushCell($sheet, $column, $row, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent, $attributeArray);
++$row;
if (isset($this->formats[$child->nodeName])) {
$sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
Expand All @@ -375,7 +395,7 @@ private function processDomElementBr(Worksheet $sheet, int &$row, string &$colum
$sheet->getStyle($column . $row)->getAlignment()->setWrapText(true);
} else {
// Otherwise flush our existing content and move the row cursor on
$this->flushCell($sheet, $column, $row, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent, $attributeArray);
++$row;
}
} else {
Expand Down Expand Up @@ -421,11 +441,11 @@ private function processDomElementH1Etc(Worksheet $sheet, int &$row, string &$co
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
} else {
if ($cellContent > '') {
$this->flushCell($sheet, $column, $row, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent, $attributeArray);
++$row;
}
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent, $attributeArray);

if (isset($this->formats[$child->nodeName])) {
$sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
Expand All @@ -448,11 +468,11 @@ private function processDomElementLi(Worksheet $sheet, int &$row, string &$colum
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
} else {
if ($cellContent > '') {
$this->flushCell($sheet, $column, $row, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent, $attributeArray);
}
++$row;
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent, $attributeArray);
$column = 'A';
}
} else {
Expand All @@ -472,7 +492,7 @@ private function processDomElementImg(Worksheet $sheet, int &$row, string &$colu
private function processDomElementTable(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
{
if ($child->nodeName === 'table') {
$this->flushCell($sheet, $column, $row, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent, $attributeArray);
$column = $this->setTableStartColumn($column);
if ($this->tableLevel > 1 && $row > 1) {
--$row;
Expand Down Expand Up @@ -574,7 +594,7 @@ private function processDomElementThTd(Worksheet $sheet, int &$row, string &$col
// apply inline style
$this->applyInlineStyle($sheet, $row, $column, $attributeArray);

$this->flushCell($sheet, $column, $row, $cellContent);
$this->flushCell($sheet, $column, $row, $cellContent, $attributeArray);

$this->processDomElementBgcolor($sheet, $row, $column, $attributeArray);
$this->processDomElementWidth($sheet, $column, $attributeArray);
Expand Down
43 changes: 43 additions & 0 deletions tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PhpOffice\PhpSpreadsheetTests\Reader\Html;

use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
Expand Down Expand Up @@ -363,4 +364,46 @@ public function testBorderWithColspan(): void
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
}
}

public function testDataType(): void
{
$html = '<table>
<tr>
<td data-type="b">1</td>
<td data-type="s">1234567</td>
<td data-type="f">=CONCAT("TEXT A ","TEXT B")</td>
PouriaSeyfi marked this conversation as resolved.
Show resolved Hide resolved
<!-- in some cases, you may want to treat the string with beginning equal sign as a string rather than a formula -->
<td data-type="s">=B1</td>
<td data-type="d">2022-02-21 10:20:30</td>
<td data-type="invalid-datatype">text</td>
</tr>
</table>';

$reader = new Html();
$spreadsheet = $reader->loadFromString($html);
$firstSheet = $spreadsheet->getSheet(0);

// check boolean data type
self::assertEquals(DataType::TYPE_BOOL, $firstSheet->getCell('A1')->getDataType());
PouriaSeyfi marked this conversation as resolved.
Show resolved Hide resolved
self::assertIsBool($firstSheet->getCell('A1')->getValue());

// check string data type
self::assertEquals(DataType::TYPE_STRING, $firstSheet->getCell('B1')->getDataType());
self::assertIsString($firstSheet->getCell('B1')->getValue());

// check formula data type
self::assertEquals(DataType::TYPE_FORMULA, $firstSheet->getCell('C1')->getDataType());

// check formula output
self::assertEquals('TEXT A TEXT B', $firstSheet->getCell('C1')->getFormattedValue());

// check string with beginning equal sign is string and not formula
self::assertEquals(DataType::TYPE_STRING, $firstSheet->getCell('D1')->getDataType());
self::assertEquals('=B1', $firstSheet->getCell('D1')->getValue());
self::assertIsString($firstSheet->getCell('D1')->getValue());
self::assertTrue($firstSheet->getCell('D1')->getStyle()->getQuotePrefix());

//check iso date
self::assertEquals($firstSheet->getCell('E1')->getValue(), 44613.43090277778);
PouriaSeyfi marked this conversation as resolved.
Show resolved Hide resolved
}
}