Merge branch 'readhtml'

This commit is contained in:
Adrien Crivelli 2020-07-26 13:11:15 +09:00
commit 4739f8b2e7
No known key found for this signature in database
GPG Key ID: B182FD79DC6DE92E
10 changed files with 965 additions and 504 deletions

View File

@ -30,7 +30,7 @@ $html1 = '<font color="#0000ff">
while this block uses an <u>underline</u>. while this block uses an <u>underline</u>.
</font> </font>
</p> </p>
<p align="right"><font size="9" color="red"> <p align="right"><font size="9" color="red" face="Times New Roman, serif">
I want to eat <ins><del>healthy food</del> <strong>pizza</strong></ins>. I want to eat <ins><del>healthy food</del> <strong>pizza</strong></ins>.
</font> </font>
'; ';

View File

@ -694,9 +694,9 @@ class Html
return implode('', $values[0]); return implode('', $values[0]);
} }
protected function colourNameLookup($rgb) public static function colourNameLookup(string $rgb): string
{ {
return self::$colourMap[$rgb]; return self::$colourMap[$rgb] ?? '';
} }
protected function startFontTag($tag): void protected function startFontTag($tag): void

View File

@ -16,6 +16,7 @@ use PhpOffice\PhpSpreadsheet\Style\Font;
use PhpOffice\PhpSpreadsheet\Style\Style; use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing; use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Throwable;
/** PhpSpreadsheet root directory */ /** PhpSpreadsheet root directory */
class Html extends BaseReader class Html extends BaseReader
@ -219,9 +220,13 @@ class Html extends BaseReader
/** /**
* Set input encoding. * Set input encoding.
* *
* @deprecated no use is made of this property
*
* @param string $pValue Input encoding, eg: 'ANSI' * @param string $pValue Input encoding, eg: 'ANSI'
* *
* @return $this * @return $this
*
* @codeCoverageIgnore
*/ */
public function setInputEncoding($pValue) public function setInputEncoding($pValue)
{ {
@ -233,7 +238,11 @@ class Html extends BaseReader
/** /**
* Get input encoding. * Get input encoding.
* *
* @deprecated no use is made of this property
*
* @return string * @return string
*
* @codeCoverageIgnore
*/ */
public function getInputEncoding() public function getInputEncoding()
{ {
@ -289,86 +298,72 @@ class Html extends BaseReader
$cellContent = (string) ''; $cellContent = (string) '';
} }
/** private function processDomElementBody(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child): void
* @param int $row
* @param string $column
* @param string $cellContent
*/
protected function processDomElement(DOMNode $element, Worksheet $sheet, &$row, &$column, &$cellContent): void
{ {
foreach ($element->childNodes as $child) {
if ($child instanceof DOMText) {
$domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue));
if (is_string($cellContent)) {
// simply append the text if the cell content is a plain text string
$cellContent .= $domText;
}
// but if we have a rich text run instead, we need to append it correctly
// TODO
} elseif ($child instanceof DOMElement) {
$attributeArray = []; $attributeArray = [];
foreach ($child->attributes as $attribute) { foreach ($child->attributes as $attribute) {
$attributeArray[$attribute->name] = $attribute->value; $attributeArray[$attribute->name] = $attribute->value;
} }
switch ($child->nodeName) { if ($child->nodeName === 'body') {
case 'meta': $row = 1;
foreach ($attributeArray as $attributeName => $attributeValue) { $column = 'A';
// Extract character set, so we can convert to UTF-8 if required $cellContent = '';
if ($attributeName === 'charset') { $this->tableLevel = 0;
$this->setInputEncoding($attributeValue);
}
}
$this->processDomElement($child, $sheet, $row, $column, $cellContent); $this->processDomElement($child, $sheet, $row, $column, $cellContent);
} else {
$this->processDomElementTitle($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
break; private function processDomElementTitle(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
case 'title': {
if ($child->nodeName === 'title') {
$this->processDomElement($child, $sheet, $row, $column, $cellContent); $this->processDomElement($child, $sheet, $row, $column, $cellContent);
$sheet->setTitle($cellContent, true, false); $sheet->setTitle($cellContent, true, false);
$cellContent = ''; $cellContent = '';
} else {
$this->processDomElementSpanEtc($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
break; private static $spanEtc = ['span', 'div', 'font', 'i', 'em', 'strong', 'b'];
case 'span':
case 'div': private function processDomElementSpanEtc(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
case 'font': {
case 'i': if (in_array($child->nodeName, self::$spanEtc)) {
case 'em':
case 'strong':
case 'b':
if (isset($attributeArray['class']) && $attributeArray['class'] === 'comment') { if (isset($attributeArray['class']) && $attributeArray['class'] === 'comment') {
$sheet->getComment($column . $row) $sheet->getComment($column . $row)
->getText() ->getText()
->createTextRun($child->textContent); ->createTextRun($child->textContent);
break;
}
if ($cellContent > '') {
$cellContent .= ' ';
} }
$this->processDomElement($child, $sheet, $row, $column, $cellContent); $this->processDomElement($child, $sheet, $row, $column, $cellContent);
if ($cellContent > '') {
$cellContent .= ' ';
}
if (isset($this->formats[$child->nodeName])) { if (isset($this->formats[$child->nodeName])) {
$sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]); $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
} }
break;
case 'hr':
$this->flushCell($sheet, $column, $row, $cellContent);
++$row;
if (isset($this->formats[$child->nodeName])) {
$sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
} else { } else {
$cellContent = '----------'; $this->processDomElementHr($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
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);
++$row;
if (isset($this->formats[$child->nodeName])) {
$sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
} }
++$row; ++$row;
// Add a break after a horizontal rule, simply by allowing the code to dropthru }
// no break // fall through to br
case 'br': $this->processDomElementBr($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
private function processDomElementBr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
{
if ($child->nodeName === 'br' || $child->nodeName === 'hr') {
if ($this->tableLevel > 0) { if ($this->tableLevel > 0) {
// If we're inside a table, replace with a \n and set the cell to wrap // If we're inside a table, replace with a \n and set the cell to wrap
$cellContent .= "\n"; $cellContent .= "\n";
@ -378,9 +373,14 @@ class Html extends BaseReader
$this->flushCell($sheet, $column, $row, $cellContent); $this->flushCell($sheet, $column, $row, $cellContent);
++$row; ++$row;
} }
} else {
$this->processDomElementA($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
break; private function processDomElementA(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
case 'a': {
if ($child->nodeName === 'a') {
foreach ($attributeArray as $attributeName => $attributeValue) { foreach ($attributeArray as $attributeName => $attributeValue) {
switch ($attributeName) { switch ($attributeName) {
case 'href': case 'href':
@ -396,22 +396,23 @@ class Html extends BaseReader
} }
} }
} }
$cellContent .= ' '; // no idea why this should be needed
//$cellContent .= ' ';
$this->processDomElement($child, $sheet, $row, $column, $cellContent); $this->processDomElement($child, $sheet, $row, $column, $cellContent);
} else {
$this->processDomElementH1Etc($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
break; private static $h1Etc = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'p'];
case 'h1':
case 'h2': private function processDomElementH1Etc(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
case 'h3': {
case 'h4': if (in_array($child->nodeName, self::$h1Etc)) {
case 'h5':
case 'h6':
case 'ol':
case 'ul':
case 'p':
if ($this->tableLevel > 0) { if ($this->tableLevel > 0) {
// If we're inside a table, replace with a \n // If we're inside a table, replace with a \n
$cellContent .= "\n"; $cellContent .= $cellContent ? "\n" : '';
$sheet->getStyle($column . $row)->getAlignment()->setWrapText(true);
$this->processDomElement($child, $sheet, $row, $column, $cellContent); $this->processDomElement($child, $sheet, $row, $column, $cellContent);
} else { } else {
if ($cellContent > '') { if ($cellContent > '') {
@ -428,12 +429,17 @@ class Html extends BaseReader
++$row; ++$row;
$column = 'A'; $column = 'A';
} }
} else {
$this->processDomElementLi($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
break; private function processDomElementLi(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
case 'li': {
if ($child->nodeName === 'li') {
if ($this->tableLevel > 0) { if ($this->tableLevel > 0) {
// If we're inside a table, replace with a \n // If we're inside a table, replace with a \n
$cellContent .= "\n"; $cellContent .= $cellContent ? "\n" : '';
$this->processDomElement($child, $sheet, $row, $column, $cellContent); $this->processDomElement($child, $sheet, $row, $column, $cellContent);
} else { } else {
if ($cellContent > '') { if ($cellContent > '') {
@ -444,13 +450,23 @@ class Html extends BaseReader
$this->flushCell($sheet, $column, $row, $cellContent); $this->flushCell($sheet, $column, $row, $cellContent);
$column = 'A'; $column = 'A';
} }
} else {
$this->processDomElementImg($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
break; private function processDomElementImg(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
case 'img': {
if ($child->nodeName === 'img') {
$this->insertImage($sheet, $column, $row, $attributeArray); $this->insertImage($sheet, $column, $row, $attributeArray);
} else {
$this->processDomElementTable($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
break; private function processDomElementTable(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
case 'table': {
if ($child->nodeName === 'table') {
$this->flushCell($sheet, $column, $row, $cellContent); $this->flushCell($sheet, $column, $row, $cellContent);
$column = $this->setTableStartColumn($column); $column = $this->setTableStartColumn($column);
if ($this->tableLevel > 1) { if ($this->tableLevel > 1) {
@ -463,14 +479,14 @@ class Html extends BaseReader
} else { } else {
++$row; ++$row;
} }
} else {
$this->processDomElementTr($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
break; private function processDomElementTr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
case 'thead': {
case 'tbody': if ($child->nodeName === 'tr') {
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
break;
case 'tr':
$column = $this->getTableStartColumn(); $column = $this->getTableStartColumn();
$cellContent = ''; $cellContent = '';
$this->processDomElement($child, $sheet, $row, $column, $cellContent); $this->processDomElement($child, $sheet, $row, $column, $cellContent);
@ -480,21 +496,88 @@ class Html extends BaseReader
} }
++$row; ++$row;
} else {
$this->processDomElementThTdOther($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
break; private function processDomElementThTdOther(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
case 'th': {
case 'td': if ($child->nodeName !== 'td' && $child->nodeName !== 'th') {
$this->processDomElement($child, $sheet, $row, $column, $cellContent); $this->processDomElement($child, $sheet, $row, $column, $cellContent);
} else {
$this->processDomElementThTd($sheet, $row, $column, $cellContent, $child, $attributeArray);
}
}
private function processDomElementBgcolor(Worksheet $sheet, int $row, string $column, array $attributeArray): void
{
if (isset($attributeArray['bgcolor'])) {
$sheet->getStyle("$column$row")->applyFromArray(
[
'fill' => [
'fillType' => Fill::FILL_SOLID,
'color' => ['rgb' => $this->getStyleColor($attributeArray['bgcolor'])],
],
]
);
}
}
private function processDomElementWidth(Worksheet $sheet, string $column, array $attributeArray): void
{
if (isset($attributeArray['width'])) {
$sheet->getColumnDimension($column)->setWidth($attributeArray['width']);
}
}
private function processDomElementHeight(Worksheet $sheet, int $row, array $attributeArray): void
{
if (isset($attributeArray['height'])) {
$sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
}
}
private function processDomElementAlign(Worksheet $sheet, int $row, string $column, array $attributeArray): void
{
if (isset($attributeArray['align'])) {
$sheet->getStyle($column . $row)->getAlignment()->setHorizontal($attributeArray['align']);
}
}
private function processDomElementVAlign(Worksheet $sheet, int $row, string $column, array $attributeArray): void
{
if (isset($attributeArray['valign'])) {
$sheet->getStyle($column . $row)->getAlignment()->setVertical($attributeArray['valign']);
}
}
private function processDomElementDataFormat(Worksheet $sheet, int $row, string $column, array $attributeArray): void
{
if (isset($attributeArray['data-format'])) {
$sheet->getStyle($column . $row)->getNumberFormat()->setFormatCode($attributeArray['data-format']);
}
}
private function processDomElementThTd(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
{
while (isset($this->rowspan[$column . $row])) { while (isset($this->rowspan[$column . $row])) {
++$column; ++$column;
} }
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
// apply inline style // apply inline style
$this->applyInlineStyle($sheet, $row, $column, $attributeArray); $this->applyInlineStyle($sheet, $row, $column, $attributeArray);
$this->flushCell($sheet, $column, $row, $cellContent); $this->flushCell($sheet, $column, $row, $cellContent);
$this->processDomElementBgcolor($sheet, $row, $column, $attributeArray);
$this->processDomElementWidth($sheet, $column, $attributeArray);
$this->processDomElementHeight($sheet, $row, $attributeArray);
$this->processDomElementAlign($sheet, $row, $column, $attributeArray);
$this->processDomElementVAlign($sheet, $row, $column, $attributeArray);
$this->processDomElementDataFormat($sheet, $row, $column, $attributeArray);
if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) { if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {
//create merging rowspan and colspan //create merging rowspan and colspan
$columnTo = $column; $columnTo = $column;
@ -522,51 +605,24 @@ class Html extends BaseReader
} }
$sheet->mergeCells($column . $row . ':' . $columnTo . $row); $sheet->mergeCells($column . $row . ':' . $columnTo . $row);
$column = $columnTo; $column = $columnTo;
} elseif (isset($attributeArray['bgcolor'])) {
$sheet->getStyle($column . $row)->applyFromArray(
[
'fill' => [
'fillType' => Fill::FILL_SOLID,
'color' => ['rgb' => $attributeArray['bgcolor']],
],
]
);
}
if (isset($attributeArray['width'])) {
$sheet->getColumnDimension($column)->setWidth($attributeArray['width']);
}
if (isset($attributeArray['height'])) {
$sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
}
if (isset($attributeArray['align'])) {
$sheet->getStyle($column . $row)->getAlignment()->setHorizontal($attributeArray['align']);
}
if (isset($attributeArray['valign'])) {
$sheet->getStyle($column . $row)->getAlignment()->setVertical($attributeArray['valign']);
}
if (isset($attributeArray['data-format'])) {
$sheet->getStyle($column . $row)->getNumberFormat()->setFormatCode($attributeArray['data-format']);
} }
++$column; ++$column;
break;
case 'body':
$row = 1;
$column = 'A';
$cellContent = '';
$this->tableLevel = 0;
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
break;
default:
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
} }
protected function processDomElement(DOMNode $element, Worksheet $sheet, int &$row, string &$column, string &$cellContent): void
{
foreach ($element->childNodes as $child) {
if ($child instanceof DOMText) {
$domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue));
if (is_string($cellContent)) {
// simply append the text if the cell content is a plain text string
$cellContent .= $domText;
}
// but if we have a rich text run instead, we need to append it correctly
// TODO
} elseif ($child instanceof DOMElement) {
$this->processDomElementBody($sheet, $row, $column, $cellContent, $child);
} }
} }
} }
@ -588,7 +644,11 @@ class Html extends BaseReader
// Create a new DOM object // Create a new DOM object
$dom = new DOMDocument(); $dom = new DOMDocument();
// Reload the HTML file into the DOM object // Reload the HTML file into the DOM object
try {
$loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scanFile($pFilename), 'HTML-ENTITIES', 'UTF-8')); $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scanFile($pFilename), 'HTML-ENTITIES', 'UTF-8'));
} catch (Throwable $e) {
$loaded = false;
}
if ($loaded === false) { if ($loaded === false) {
throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document'); throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document');
} }
@ -606,7 +666,11 @@ class Html extends BaseReader
// Create a new DOM object // Create a new DOM object
$dom = new DOMDocument(); $dom = new DOMDocument();
// Reload the HTML file into the DOM object // Reload the HTML file into the DOM object
try {
$loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scan($content), 'HTML-ENTITIES', 'UTF-8')); $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scan($content), 'HTML-ENTITIES', 'UTF-8'));
} catch (Throwable $e) {
$loaded = false;
}
if ($loaded === false) { if ($loaded === false) {
throw new Exception('Failed to load content as a DOM Document'); throw new Exception('Failed to load content as a DOM Document');
} }
@ -856,7 +920,7 @@ class Html extends BaseReader
return substr($value, 1); return substr($value, 1);
} }
return null; return \PhpOffice\PhpSpreadsheet\Helper\Html::colourNameLookup((string) $value);
} }
/** /**
@ -872,7 +936,7 @@ class Html extends BaseReader
$src = urldecode($attributes['src']); $src = urldecode($attributes['src']);
$width = isset($attributes['width']) ? (float) $attributes['width'] : null; $width = isset($attributes['width']) ? (float) $attributes['width'] : null;
$height = isset($attributes['height']) ? (float) $attributes['height'] : null; $height = isset($attributes['height']) ? (float) $attributes['height'] : null;
$name = isset($attributes['alt']) ? (float) $attributes['alt'] : null; $name = $attributes['alt'] ?? null;
$drawing = new Drawing(); $drawing = new Drawing();
$drawing->setPath($src); $drawing->setPath($src);
@ -903,6 +967,28 @@ class Html extends BaseReader
); );
} }
private static $borderMappings = [
'dash-dot' => Border::BORDER_DASHDOT,
'dash-dot-dot' => Border::BORDER_DASHDOTDOT,
'dashed' => Border::BORDER_DASHED,
'dotted' => Border::BORDER_DOTTED,
'double' => Border::BORDER_DOUBLE,
'hair' => Border::BORDER_HAIR,
'medium' => Border::BORDER_MEDIUM,
'medium-dashed' => Border::BORDER_MEDIUMDASHED,
'medium-dash-dot' => Border::BORDER_MEDIUMDASHDOT,
'medium-dash-dot-dot' => Border::BORDER_MEDIUMDASHDOTDOT,
'none' => Border::BORDER_NONE,
'slant-dash-dot' => Border::BORDER_SLANTDASHDOT,
'solid' => Border::BORDER_THIN,
'thick' => Border::BORDER_THICK,
];
public static function getBorderMappings(): array
{
return self::$borderMappings;
}
/** /**
* Map html border style to PhpSpreadsheet border style. * Map html border style to PhpSpreadsheet border style.
* *
@ -912,38 +998,7 @@ class Html extends BaseReader
*/ */
public function getBorderStyle($style) public function getBorderStyle($style)
{ {
switch ($style) { return (array_key_exists($style, self::$borderMappings)) ? self::$borderMappings[$style] : null;
case 'solid':
return Border::BORDER_THIN;
case 'dashed':
return Border::BORDER_DASHED;
case 'dotted':
return Border::BORDER_DOTTED;
case 'medium':
return Border::BORDER_MEDIUM;
case 'thick':
return Border::BORDER_THICK;
case 'none':
return Border::BORDER_NONE;
case 'dash-dot':
return Border::BORDER_DASHDOT;
case 'dash-dot-dot':
return Border::BORDER_DASHDOTDOT;
case 'double':
return Border::BORDER_DOUBLE;
case 'hair':
return Border::BORDER_HAIR;
case 'medium-dash-dot':
return Border::BORDER_MEDIUMDASHDOT;
case 'medium-dash-dot-dot':
return Border::BORDER_MEDIUMDASHDOTDOT;
case 'medium-dashed':
return Border::BORDER_MEDIUMDASHED;
case 'slant-dash-dot':
return Border::BORDER_SLANTDASHDOT;
}
return null;
} }
/** /**

View File

@ -0,0 +1,110 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Html;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PHPUnit\Framework\TestCase;
class HtmlBorderTest extends TestCase
{
public function testCanApplyInlineBordersStyles(): void
{
$html = '<table>
<tr>
<td style="border: 1px solid #333333;">Thin border</td>
<td style="border-bottom: 1px dashed #333333;">Border bottom</td>
<td style="border-top: 1px solid #333333;">Border top</td>
<td style="border-left: 1px solid green;">Border left</td>
<td style="border-right: 1px solid #333333;">Border right</td>
<td style="border: none"></td>
</tr>
</table>';
$filename = HtmlHelper::createHtml($html);
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0);
$style = $firstSheet->getCell('A1')->getStyle();
$borders = $style->getBorders();
/** @var Border $border */
foreach ([$borders->getTop(), $borders->getBottom(), $borders->getLeft(), $borders->getRight()] as $border) {
self::assertEquals('333333', $border->getColor()->getRGB());
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
}
$style = $firstSheet->getCell('B1')->getStyle();
$border = $style->getBorders()->getBottom();
self::assertEquals('333333', $border->getColor()->getRGB());
self::assertEquals(Border::BORDER_DASHED, $border->getBorderStyle());
self::assertEquals(Border::BORDER_NONE, $style->getBorders()->getTop()->getBorderStyle());
$style = $firstSheet->getCell('C1')->getStyle();
$border = $style->getBorders()->getTop();
self::assertEquals('333333', $border->getColor()->getRGB());
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
self::assertEquals(Border::BORDER_NONE, $style->getBorders()->getBottom()->getBorderStyle());
$style = $firstSheet->getCell('D1')->getStyle();
$border = $style->getBorders()->getLeft();
self::assertEquals('00ff00', $border->getColor()->getRGB());
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
self::assertEquals(Border::BORDER_NONE, $style->getBorders()->getBottom()->getBorderStyle());
$style = $firstSheet->getCell('E1')->getStyle();
$border = $style->getBorders()->getRight();
self::assertEquals('333333', $border->getColor()->getRGB());
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
self::assertEquals(Border::BORDER_NONE, $style->getBorders()->getBottom()->getBorderStyle());
$style = $firstSheet->getCell('F1')->getStyle();
$borders = $style->getBorders();
foreach ([$borders->getTop(), $borders->getBottom(), $borders->getLeft(), $borders->getRight()] as $border) {
self::assertEquals(Border::BORDER_NONE, $border->getBorderStyle());
}
}
/**
* @dataProvider providerBorderStyle
*/
public function testBorderStyle(string $style, string $expectedResult): void
{
$borders = Html::getBorderMappings();
self::assertEquals($expectedResult, $borders[$style]);
}
public function testBorderStyleCoverage(): void
{
$expected = Html::getBorderMappings();
$covered = [];
foreach ($expected as $key => $val) {
$covered[$key] = 0;
}
$tests = $this->providerBorderStyle();
foreach ($tests as $test) {
$covered[$test[0]] = 1;
}
foreach ($covered as $key => $val) {
self::assertEquals(1, $val, "Borderstyle $key not tested");
}
}
public function providerBorderStyle(): array
{
return [
['dash-dot', Border::BORDER_DASHDOT],
['dash-dot-dot', Border::BORDER_DASHDOTDOT],
['dashed', Border::BORDER_DASHED],
['dotted', Border::BORDER_DOTTED],
['double', Border::BORDER_DOUBLE],
['hair', Border::BORDER_HAIR],
['medium', Border::BORDER_MEDIUM],
['medium-dashed', Border::BORDER_MEDIUMDASHED],
['medium-dash-dot', Border::BORDER_MEDIUMDASHDOT],
['medium-dash-dot-dot', Border::BORDER_MEDIUMDASHDOTDOT],
['none', Border::BORDER_NONE],
['slant-dash-dot', Border::BORDER_SLANTDASHDOT],
['solid', Border::BORDER_THIN],
['thick', Border::BORDER_THICK],
];
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Html;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
class HtmlHelper
{
public static function createHtml(string $html): string
{
$filename = tempnam(sys_get_temp_dir(), 'html');
file_put_contents($filename, $html);
return $filename;
}
public static function loadHtmlIntoSpreadsheet(string $filename, bool $unlink = false): Spreadsheet
{
$html = new Html();
$spreadsheet = $html->load($filename);
if ($unlink) {
unlink($filename);
}
return $spreadsheet;
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Html;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PHPUnit\Framework\TestCase;
class HtmlImageTest extends TestCase
{
public function testCanInsertImage(): void
{
$imagePath = realpath(__DIR__ . '/../../../data/Reader/HTML/image.jpg');
$html = '<table>
<tr>
<td><img src="' . $imagePath . '" alt="test image"></td>
</tr>
</table>';
$filename = HtmlHelper::createHtml($html);
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0);
/** @var Drawing $drawing */
$drawing = $firstSheet->getDrawingCollection()[0];
self::assertEquals($imagePath, $drawing->getPath());
self::assertEquals('A1', $drawing->getCoordinates());
self::assertEquals('test image', $drawing->getName());
self::assertEquals('100', $drawing->getWidth());
self::assertEquals('100', $drawing->getHeight());
}
public function testCanInsertImageWidth(): void
{
$imagePath = realpath(__DIR__ . '/../../../data/Reader/HTML/image.jpg');
$html = '<table>
<tr>
<td><img src="' . $imagePath . '" alt="test image" width="50"></td>
</tr>
</table>';
$filename = HtmlHelper::createHtml($html);
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0);
/** @var Drawing $drawing */
$drawing = $firstSheet->getDrawingCollection()[0];
self::assertEquals('50', $drawing->getWidth());
self::assertEquals('50', $drawing->getHeight());
}
public function testCanInsertImageHeight(): void
{
$imagePath = realpath(__DIR__ . '/../../../data/Reader/HTML/image.jpg');
$html = '<table>
<tr>
<td><img src="' . $imagePath . '" height="75"></td>
</tr>
</table>';
$filename = HtmlHelper::createHtml($html);
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0);
/** @var Drawing $drawing */
$drawing = $firstSheet->getDrawingCollection()[0];
self::assertEquals('', $drawing->getName());
self::assertEquals('75', $drawing->getWidth());
self::assertEquals('75', $drawing->getHeight());
}
public function testImageWithourSrc(): void
{
$html = '<table>
<tr>
<td><img></td>
</tr>
</table>';
$filename = HtmlHelper::createHtml($html);
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0);
self::assertCount(0, $firstSheet->getDrawingCollection());
}
}

View File

@ -0,0 +1,92 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Html;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use PHPUnit\Framework\TestCase;
class HtmlLoadStringTest extends TestCase
{
public function testCanLoadFromString(): void
{
$html = '<table>
<tr>
<td>Hello World</td>
</tr>
<tr>
<td>Hello<br />World</td>
</tr>
<tr>
<td>Hello<br>World</td>
</tr>
</table>';
$spreadsheet = (new Html())->loadFromString($html);
$firstSheet = $spreadsheet->getSheet(0);
$cellStyle = $firstSheet->getStyle('A1');
self::assertFalse($cellStyle->getAlignment()->getWrapText());
$cellStyle = $firstSheet->getStyle('A2');
self::assertTrue($cellStyle->getAlignment()->getWrapText());
$cellValue = $firstSheet->getCell('A2')->getValue();
self::assertStringContainsString("\n", $cellValue);
$cellStyle = $firstSheet->getStyle('A3');
self::assertTrue($cellStyle->getAlignment()->getWrapText());
$cellValue = $firstSheet->getCell('A3')->getValue();
self::assertStringContainsString("\n", $cellValue);
}
public function testLoadInvalidString(): void
{
$this->expectException(ReaderException::class);
$html = '<table<>';
$spreadsheet = (new Html())->loadFromString($html);
$firstSheet = $spreadsheet->getSheet(0);
$cellStyle = $firstSheet->getStyle('A1');
self::assertFalse($cellStyle->getAlignment()->getWrapText());
}
public function testCanLoadFromStringIntoExistingSpreadsheet(): void
{
$html = '<table>
<tr>
<td>Hello World</td>
</tr>
<tr>
<td>Hello<br />World</td>
</tr>
<tr>
<td>Hello<br>World</td>
</tr>
</table>';
$reader = new Html();
$spreadsheet = $reader->loadFromString($html);
$firstSheet = $spreadsheet->getSheet(0);
$cellStyle = $firstSheet->getStyle('A1');
self::assertFalse($cellStyle->getAlignment()->getWrapText());
$cellStyle = $firstSheet->getStyle('A2');
self::assertTrue($cellStyle->getAlignment()->getWrapText());
$cellValue = $firstSheet->getCell('A2')->getValue();
self::assertStringContainsString("\n", $cellValue);
$cellStyle = $firstSheet->getStyle('A3');
self::assertTrue($cellStyle->getAlignment()->getWrapText());
$cellValue = $firstSheet->getCell('A3')->getValue();
self::assertStringContainsString("\n", $cellValue);
$reader->setSheetIndex(1);
$html = '<table>
<tr>
<td>Goodbye World</td>
</tr>
</table>';
self::assertEquals(1, $spreadsheet->getSheetCount());
$spreadsheet = $reader->loadFromString($html, $spreadsheet);
self::assertEquals(2, $spreadsheet->getSheetCount());
}
}

View File

@ -0,0 +1,236 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Html;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PHPUnit\Framework\TestCase;
class HtmlTagsTest extends TestCase
{
public function testTags(): void
{
$reader = new Html();
$html1 = <<<EOF
<table><tbody>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td><a href='www.google.com'>hyperlink</a></td><td>5<hr></td><td>6</td></tr>
<tr><td>7</td><td>8</td><td>9</td></tr>
<tr><td>10</td><td>11</td><td>12</td></tr>
</tbody></table>
<hr>
<table><tbody>
<tr><td>1</td><td><i>2</i></td><td>3</td></tr>
<tr height='20'><td>4</td><td>5</td><td>6</td></tr>
<tr><td>7</td><td>8</td><td>9</td></tr>
<tr><td><ul><li>A</li><li>B</li><li>C</li></ul></td><td>11</td><td>12</td></tr>
</tbody></table>
<ul><li>D</li><li>E</li><li>F</li></ul>
<br>
<table><tbody>
<tr><td>M</td>
<td>
<table><tbody>
<tr><td>N</td><td>O</td></tr>
<tr><td>P</td><td>Q</td></tr>
</tbody></table>
</td>
<td>R</td>
</tr>
<tr><td>S</td><td>T</td><td>U</td></tr>
</tbody></table>
EOF;
$robj = $reader->loadFromString($html1);
$sheet = $robj->getActiveSheet();
self::assertEquals('www.google.com', $sheet->getCell('A2')->getHyperlink()->getUrl());
self::assertEquals('hyperlink', $sheet->getCell('A2')->getValue());
self::assertEquals(-1, $sheet->getRowDimension(11)->getRowHeight());
self::assertEquals(20, $sheet->getRowDimension(12)->getRowHeight());
self::assertEquals(5, $sheet->getCell('B2')->getValue());
self::assertEquals(Border::BORDER_THIN, $sheet->getCell('B3')->getStyle()->getBorders()->getBottom()->getBorderStyle());
self::assertEquals(6, $sheet->getCell('C4')->getValue());
self::assertEquals(Border::BORDER_THIN, $sheet->getCell('A9')->getStyle()->getBorders()->getBottom()->getBorderStyle());
self::assertEquals(2, $sheet->getCell('B11')->getValue());
self::assertTrue($sheet->getCell('B11')->getStyle()->getFont()->getItalic());
// list within table
self::assertEquals("A\nB\nC", $sheet->getCell('A14')->getValue());
self::assertTrue($sheet->getCell('A14')->getStyle()->getAlignment()->getWrapText());
// list outside of table
self::assertEquals('D', $sheet->getCell('A17')->getValue());
self::assertEquals('E', $sheet->getCell('A18')->getValue());
self::assertEquals('F', $sheet->getCell('A19')->getValue());
// embedded table
self::assertEquals('M', $sheet->getCell('A21')->getValue());
self::assertEquals('N', $sheet->getCell('B20')->getValue());
self::assertEquals('O', $sheet->getCell('C20')->getValue());
self::assertEquals('P', $sheet->getCell('B21')->getValue());
self::assertEquals('Q', $sheet->getCell('C21')->getValue());
self::assertEquals('R', $sheet->getCell('C23')->getValue());
self::assertEquals('S', $sheet->getCell('A24')->getValue());
}
public static function testTagsRowColSpans(): void
{
$reader = new Html();
$html1 = <<<EOF
<table>
<tr>
<th>Month</th>
<th>Savings</th>
<th>Expenses</th>
</tr>
<tr>
<td>January</td>
<td>$100</td>
<td rowspan="2">$50</td>
</tr>
<tr>
<td>February</td>
<td>$80</td>
</tr>
<tr>
<td rowspan="2" colspan="2" bgcolor="#00FFFF">Away in March</td>
<td>$30</td>
</tr>
<tr>
<td>$40</td>
</tr>
</table>
EOF;
$robj = $reader->loadFromString($html1);
$sheet = $robj->getActiveSheet();
self::assertEquals(['C2:C3' => 'C2:C3', 'A4:B5' => 'A4:B5'], $sheet->getMergeCells());
self::assertEquals('Away in March', $sheet->getCell('A4')->getValue());
self::assertEquals('00FFFF', $sheet->getCell('A4')->getStyle()->getFill()->getEndColor()->getRGB());
}
public static function testDoublyEmbeddedTable(): void
{
$reader = new Html();
$html1 = <<<EOF
<table><tbody>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>4</td><td>5</td><td>6</td></tr>
<tr><td>7</td><td>8</td><td>9</td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td>M</td>
<td>
<table><tbody>
<tr><td>N</td>
<td>
<table><tbody>
<tr><td>10</td><td>11</td></tr>
<tr><td>12</td><td>13</td></tr>
</tbody></table>
</td>
<td>Y</td>
</tr>
<tr><td>P</td><td>Q</td><td>X</td></tr>
</tbody></table>
</td>
<td>R</td>
</tr>
<tr><td>S</td><td>T</td><td>U</td></tr>
</tbody></table>
EOF;
$robj = $reader->loadFromString($html1);
$sheet = $robj->getActiveSheet();
self::assertEquals('1', $sheet->getCell('A1')->getValue());
self::assertEquals('2', $sheet->getCell('B1')->getValue());
self::assertEquals('3', $sheet->getCell('C1')->getValue());
self::assertEquals('4', $sheet->getCell('A2')->getValue());
self::assertEquals('5', $sheet->getCell('B2')->getValue());
self::assertEquals('6', $sheet->getCell('C2')->getValue());
self::assertEquals('7', $sheet->getCell('A3')->getValue());
self::assertEquals('8', $sheet->getCell('B3')->getValue());
self::assertEquals('9', $sheet->getCell('C3')->getValue());
self::assertEquals('10', $sheet->getCell('C5')->getValue());
self::assertEquals('11', $sheet->getCell('D5')->getValue());
self::assertEquals('12', $sheet->getCell('C6')->getValue());
self::assertEquals('13', $sheet->getCell('D6')->getValue());
self::assertEquals('N', $sheet->getCell('B6')->getValue());
self::assertEquals('M', $sheet->getCell('A7')->getValue());
self::assertEquals('Y', $sheet->getCell('E7')->getValue());
self::assertEquals('P', $sheet->getCell('B8')->getValue());
self::assertEquals('Q', $sheet->getCell('C8')->getValue());
self::assertEquals('X', $sheet->getCell('D8')->getValue());
self::assertEquals('R', $sheet->getCell('C10')->getValue());
self::assertEquals('S', $sheet->getCell('A11')->getValue());
self::assertEquals('T', $sheet->getCell('B11')->getValue());
self::assertEquals('U', $sheet->getCell('C11')->getValue());
}
public static function testTagsOutsideTable(): void
{
$reader = new Html();
$html1 = <<<EOF
<h1>Here comes a list</h1>
<ol>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ol>
And here's another
<ul>
<li>Item A</li>
<li>Item B</li>
</ul>
<ol>
Content before list
<li>Item I</li>
<li>Item II</li>
<li>This <i>is</i> <span style='color: #ff0000;'>rich</span> text</li>
</ol>
EOF;
$robj = $reader->loadFromString($html1);
$sheet = $robj->getActiveSheet();
self::assertTrue($sheet->getCell('A1')->getStyle()->getFont()->getBold());
self::assertEquals('Here comes a list', $sheet->getCell('A1')->getValue());
self::assertEquals('Item 1', $sheet->getCell('A3')->getValue());
self::assertEquals('Item 2', $sheet->getCell('A4')->getValue());
self::assertEquals('Item 3', $sheet->getCell('A5')->getValue());
self::assertEquals('Item 4', $sheet->getCell('A6')->getValue());
self::assertEquals('And here\'s another', $sheet->getCell('A7')->getValue());
self::assertEquals('Item A', $sheet->getCell('A9')->getValue());
self::assertEquals('Item B', $sheet->getCell('A10')->getValue());
self::assertEquals('Content before list', $sheet->getCell('A11')->getValue());
self::assertEquals('Item I', $sheet->getCell('A12')->getValue());
self::assertEquals('Item II', $sheet->getCell('A13')->getValue());
// TODO Rich Text not yet supported
}
public static function testHyperlinksWithRowspan(): void
{
$reader = new Html();
$html1 = <<<EOF
<table>
<tr>
<td rowspan="3">Title</td>
<td><a href="https://google.com">Link 1</a></td>
</tr>
<tr>
<td><a href="https://google.com">Link 2</a></td>
</tr>
<tr>
<td><a href="https://google.com">Link 3</a></td>
</tr>
</table>
EOF;
$robj = $reader->loadFromString($html1);
$sheet = $robj->getActiveSheet();
self::assertEquals('https://google.com', $sheet->getCell('B1')->getHyperlink()->getUrl());
self::assertEquals('https://google.com', $sheet->getCell('B2')->getHyperlink()->getUrl());
self::assertEquals('https://google.com', $sheet->getCell('B3')->getHyperlink()->getUrl());
}
}

View File

@ -1,12 +1,11 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Reader; namespace PhpOffice\PhpSpreadsheetTests\Reader\Html;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
use PhpOffice\PhpSpreadsheet\Reader\Html; use PhpOffice\PhpSpreadsheet\Reader\Html;
use PhpOffice\PhpSpreadsheet\Style\Alignment; use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Font; use PhpOffice\PhpSpreadsheet\Style\Font;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class HtmlTest extends TestCase class HtmlTest extends TestCase
@ -18,6 +17,33 @@ class HtmlTest extends TestCase
self::assertFalse($reader->canRead($filename)); self::assertFalse($reader->canRead($filename));
} }
public function testBadHtml(): void
{
$this->expectException(ReaderException::class);
$filename = 'tests/data/Reader/HTML/badhtml.html';
$reader = new Html();
self::assertTrue($reader->canRead($filename));
$reader->load($filename);
self::assertTrue(false);
}
public function testNonHtml(): void
{
$this->expectException(ReaderException::class);
$filename = __FILE__;
$reader = new Html();
self::assertFalse($reader->canRead($filename));
$reader->load($filename);
self::assertTrue(false);
}
public function testInvalidFilename(): void
{
$reader = new Html();
self::assertEquals(0, $reader->getSheetIndex());
self::assertFalse($reader->canRead(''));
}
public function providerCanReadVerySmallFile() public function providerCanReadVerySmallFile()
{ {
$padding = str_repeat('a', 2048); $padding = str_repeat('a', 2048);
@ -38,7 +64,7 @@ class HtmlTest extends TestCase
*/ */
public function testCanReadVerySmallFile($expected, $content): void public function testCanReadVerySmallFile($expected, $content): void
{ {
$filename = $this->createHtml($content); $filename = HtmlHelper::createHtml($content);
$reader = new Html(); $reader = new Html();
$actual = $reader->canRead($filename); $actual = $reader->canRead($filename);
@ -51,63 +77,21 @@ class HtmlTest extends TestCase
{ {
$html = '<table> $html = '<table>
<tr> <tr>
<td style="background-color: #000000;color: #FFFFFF">Blue background</td> <td style="background-color: #0000FF;color: #FFFFFF">Blue background</td>
<td style="background-color: unknown1;color: unknown2">Unknown fore/background</td>
</tr> </tr>
</table>'; </table>';
$filename = $this->createHtml($html); $filename = HtmlHelper::createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$style = $firstSheet->getCell('A1')->getStyle(); $style = $firstSheet->getCell('A1')->getStyle();
self::assertEquals('FFFFFF', $style->getFont()->getColor()->getRGB()); self::assertEquals('FFFFFF', $style->getFont()->getColor()->getRGB());
self::assertEquals('0000FF', $style->getFill()->getStartColor()->getRGB());
unlink($filename); self::assertEquals('0000FF', $style->getFill()->getEndColor()->getRGB());
}
public function testCanApplyInlineBordersStyles(): void
{
$html = '<table>
<tr>
<td style="border: 1px solid #333333;">Thin border</td>
<td style="border-bottom: 1px solid #333333;">Border bottom</td>
<td style="border-top: 1px solid #333333;">Border top</td>
<td style="border-left: 1px solid #333333;">Border left</td>
<td style="border-right: 1px solid #333333;">Border right</td>
</tr>
</table>';
$filename = $this->createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename);
$firstSheet = $spreadsheet->getSheet(0);
$style = $firstSheet->getCell('A1')->getStyle();
$borders = $style->getBorders();
/** @var Border $border */
foreach ([$borders->getTop(), $borders->getBottom(), $borders->getLeft(), $borders->getRight()] as $border) {
self::assertEquals('333333', $border->getColor()->getRGB());
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
}
$style = $firstSheet->getCell('B1')->getStyle(); $style = $firstSheet->getCell('B1')->getStyle();
$border = $style->getBorders()->getBottom(); self::assertEquals('000000', $style->getFont()->getColor()->getRGB());
self::assertEquals('333333', $border->getColor()->getRGB()); self::assertEquals('000000', $style->getFill()->getEndColor()->getRGB());
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle()); self::assertEquals('FFFFFF', $style->getFill()->getstartColor()->getRGB());
$style = $firstSheet->getCell('C1')->getStyle();
$border = $style->getBorders()->getTop();
self::assertEquals('333333', $border->getColor()->getRGB());
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
$style = $firstSheet->getCell('D1')->getStyle();
$border = $style->getBorders()->getLeft();
self::assertEquals('333333', $border->getColor()->getRGB());
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
$style = $firstSheet->getCell('E1')->getStyle();
$border = $style->getBorders()->getRight();
self::assertEquals('333333', $border->getColor()->getRGB());
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
unlink($filename);
} }
public function testCanApplyInlineFontStyles(): void public function testCanApplyInlineFontStyles(): void
@ -122,8 +106,8 @@ class HtmlTest extends TestCase
<td style="text-decoration: line-through;">Line through</td> <td style="text-decoration: line-through;">Line through</td>
</tr> </tr>
</table>'; </table>';
$filename = $this->createHtml($html); $filename = HtmlHelper::createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$style = $firstSheet->getCell('A1')->getStyle(); $style = $firstSheet->getCell('A1')->getStyle();
@ -143,8 +127,6 @@ class HtmlTest extends TestCase
$style = $firstSheet->getCell('F1')->getStyle(); $style = $firstSheet->getCell('F1')->getStyle();
self::assertTrue($style->getFont()->getStrikethrough()); self::assertTrue($style->getFont()->getStrikethrough());
unlink($filename);
} }
public function testCanApplyInlineWidth(): void public function testCanApplyInlineWidth(): void
@ -155,8 +137,8 @@ class HtmlTest extends TestCase
<td style="width: 100px;">100px</td> <td style="width: 100px;">100px</td>
</tr> </tr>
</table>'; </table>';
$filename = $this->createHtml($html); $filename = HtmlHelper::createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$dimension = $firstSheet->getColumnDimension('A'); $dimension = $firstSheet->getColumnDimension('A');
@ -164,8 +146,6 @@ class HtmlTest extends TestCase
$dimension = $firstSheet->getColumnDimension('B'); $dimension = $firstSheet->getColumnDimension('B');
self::assertEquals(100, $dimension->getWidth()); self::assertEquals(100, $dimension->getWidth());
unlink($filename);
} }
public function testCanApplyInlineHeight(): void public function testCanApplyInlineHeight(): void
@ -178,8 +158,8 @@ class HtmlTest extends TestCase
<td style="height: 100px;">2</td> <td style="height: 100px;">2</td>
</tr> </tr>
</table>'; </table>';
$filename = $this->createHtml($html); $filename = HtmlHelper::createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$dimension = $firstSheet->getRowDimension(1); $dimension = $firstSheet->getRowDimension(1);
@ -187,8 +167,6 @@ class HtmlTest extends TestCase
$dimension = $firstSheet->getRowDimension(2); $dimension = $firstSheet->getRowDimension(2);
self::assertEquals(100, $dimension->getRowHeight()); self::assertEquals(100, $dimension->getRowHeight());
unlink($filename);
} }
public function testCanApplyAlignment(): void public function testCanApplyAlignment(): void
@ -203,8 +181,8 @@ class HtmlTest extends TestCase
<td style="word-wrap: break-word;">Wraptext</td> <td style="word-wrap: break-word;">Wraptext</td>
</tr> </tr>
</table>'; </table>';
$filename = $this->createHtml($html); $filename = HtmlHelper::createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$style = $firstSheet->getCell('A1')->getStyle(); $style = $firstSheet->getCell('A1')->getStyle();
@ -224,8 +202,6 @@ class HtmlTest extends TestCase
$style = $firstSheet->getCell('F1')->getStyle(); $style = $firstSheet->getCell('F1')->getStyle();
self::assertTrue($style->getAlignment()->getWrapText()); self::assertTrue($style->getAlignment()->getWrapText());
unlink($filename);
} }
public function testCanApplyInlineDataFormat(): void public function testCanApplyInlineDataFormat(): void
@ -235,35 +211,12 @@ class HtmlTest extends TestCase
<td data-format="mmm-yy">2019-02-02 12:34:00</td> <td data-format="mmm-yy">2019-02-02 12:34:00</td>
</tr> </tr>
</table>'; </table>';
$filename = $this->createHtml($html); $filename = HtmlHelper::createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$style = $firstSheet->getCell('A1')->getStyle(); $style = $firstSheet->getCell('A1')->getStyle();
self::assertEquals('mmm-yy', $style->getNumberFormat()->getFormatCode()); self::assertEquals('mmm-yy', $style->getNumberFormat()->getFormatCode());
unlink($filename);
}
public function testCanInsertImage(): void
{
$imagePath = realpath(__DIR__ . '/../../data/Reader/HTML/image.jpg');
$html = '<table>
<tr>
<td><img src="' . $imagePath . '" alt=""></td>
</tr>
</table>';
$filename = $this->createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename);
$firstSheet = $spreadsheet->getSheet(0);
/** @var Drawing $drawing */
$drawing = $firstSheet->getDrawingCollection()[0];
self::assertEquals($imagePath, $drawing->getPath());
self::assertEquals('A1', $drawing->getCoordinates());
unlink($filename);
} }
public function testCanApplyCellWrapping(): void public function testCanApplyCellWrapping(): void
@ -279,8 +232,8 @@ class HtmlTest extends TestCase
<td>Hello<br>World</td> <td>Hello<br>World</td>
</tr> </tr>
</table>'; </table>';
$filename = $this->createHtml($html); $filename = HtmlHelper::createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$cellStyle = $firstSheet->getStyle('A1'); $cellStyle = $firstSheet->getStyle('A1');
@ -295,103 +248,6 @@ class HtmlTest extends TestCase
self::assertTrue($cellStyle->getAlignment()->getWrapText()); self::assertTrue($cellStyle->getAlignment()->getWrapText());
$cellValue = $firstSheet->getCell('A3')->getValue(); $cellValue = $firstSheet->getCell('A3')->getValue();
self::assertStringContainsString("\n", $cellValue); self::assertStringContainsString("\n", $cellValue);
unlink($filename);
}
public function testCanLoadFromString(): void
{
$html = '<table>
<tr>
<td>Hello World</td>
</tr>
<tr>
<td>Hello<br />World</td>
</tr>
<tr>
<td>Hello<br>World</td>
</tr>
</table>';
$spreadsheet = (new Html())->loadFromString($html);
$firstSheet = $spreadsheet->getSheet(0);
$cellStyle = $firstSheet->getStyle('A1');
self::assertFalse($cellStyle->getAlignment()->getWrapText());
$cellStyle = $firstSheet->getStyle('A2');
self::assertTrue($cellStyle->getAlignment()->getWrapText());
$cellValue = $firstSheet->getCell('A2')->getValue();
self::assertStringContainsString("\n", $cellValue);
$cellStyle = $firstSheet->getStyle('A3');
self::assertTrue($cellStyle->getAlignment()->getWrapText());
$cellValue = $firstSheet->getCell('A3')->getValue();
self::assertStringContainsString("\n", $cellValue);
}
public function testCanLoadFromStringIntoExistingSpreadsheet(): void
{
$html = '<table>
<tr>
<td>Hello World</td>
</tr>
<tr>
<td>Hello<br />World</td>
</tr>
<tr>
<td>Hello<br>World</td>
</tr>
</table>';
$reader = new Html();
$spreadsheet = $reader->loadFromString($html);
$firstSheet = $spreadsheet->getSheet(0);
$cellStyle = $firstSheet->getStyle('A1');
self::assertFalse($cellStyle->getAlignment()->getWrapText());
$cellStyle = $firstSheet->getStyle('A2');
self::assertTrue($cellStyle->getAlignment()->getWrapText());
$cellValue = $firstSheet->getCell('A2')->getValue();
self::assertStringContainsString("\n", $cellValue);
$cellStyle = $firstSheet->getStyle('A3');
self::assertTrue($cellStyle->getAlignment()->getWrapText());
$cellValue = $firstSheet->getCell('A3')->getValue();
self::assertStringContainsString("\n", $cellValue);
$reader->setSheetIndex(1);
$html = '<table>
<tr>
<td>Goodbye World</td>
</tr>
</table>';
self::assertEquals(1, $spreadsheet->getSheetCount());
$spreadsheet = $reader->loadFromString($html, $spreadsheet);
self::assertEquals(2, $spreadsheet->getSheetCount());
}
/**
* @param string $html
*
* @return string
*/
private function createHtml($html)
{
$filename = tempnam(sys_get_temp_dir(), 'html');
file_put_contents($filename, $html);
return $filename;
}
/**
* @param $filename
*
* @return \PhpOffice\PhpSpreadsheet\Spreadsheet
*/
private function loadHtmlIntoSpreadsheet($filename)
{
return (new Html())->load($filename);
} }
public function testRowspanInRendering(): void public function testRowspanInRendering(): void
@ -417,12 +273,11 @@ class HtmlTest extends TestCase
<td style="text-indent:10px">Text Indent</td> <td style="text-indent:10px">Text Indent</td>
</tr> </tr>
</table>'; </table>';
$filename = $this->createHtml($html); $filename = HtmlHelper::createHtml($html);
$spreadsheet = $this->loadHtmlIntoSpreadsheet($filename); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$style = $firstSheet->getCell('C2')->getStyle(); $style = $firstSheet->getCell('C2')->getStyle();
self::assertEquals(10, $style->getAlignment()->getIndent()); self::assertEquals(10, $style->getAlignment()->getIndent());
unlink($filename);
} }
public function testBorderWithRowspanAndColspan(): void public function testBorderWithRowspanAndColspan(): void

View File

@ -0,0 +1 @@
<table<>