diff --git a/samples/Basic/20_Read_Excel2003XML.php b/samples/Basic/20_Read_Excel2003XML.php
index 44425e20a5..48ac3373c5 100644
--- a/samples/Basic/20_Read_Excel2003XML.php
+++ b/samples/Basic/20_Read_Excel2003XML.php
@@ -4,7 +4,7 @@
require __DIR__ . '/../Header.php';
-$filename = __DIR__ . '/../templates/Excel2003XMLTest.xml';
+$filename = __DIR__ . '/../templates/excel2003.xml';
$callStartTime = microtime(true);
$spreadsheet = IOFactory::load($filename);
$helper->logRead('Xml', $filename, $callStartTime);
diff --git a/tests/data/Reader/Xml/WithoutStyle.xml b/samples/templates/excel2003.short.bad.xml
similarity index 66%
rename from tests/data/Reader/Xml/WithoutStyle.xml
rename to samples/templates/excel2003.short.bad.xml
index b8698b0497..bd9674bc3a 100644
--- a/tests/data/Reader/Xml/WithoutStyle.xml
+++ b/samples/templates/excel2003.short.bad.xml
@@ -20,6 +20,19 @@
False
False
+
+
+
+
@@ -28,7 +41,7 @@
-
+
Test String 1
@@ -38,7 +51,16 @@
|
- 1
+ 1
+ |
+
+ 12
+ |
+
+ 11
+ |
+
+ 1960-12-19T00:00:00.000
|
diff --git a/samples/templates/excel2003.xml b/samples/templates/excel2003.xml
new file mode 100644
index 0000000000..cd1188a72b
--- /dev/null
+++ b/samples/templates/excel2003.xml
@@ -0,0 +1,944 @@
+
+
+
+
+ Xml2003 Workbook
+ Test Gnumeric Workbook Subject
+ Mark Baker
+ PHPExcel Xml Reader Test Keywords
+ Some comments about the PHPExcel Gnumeric Reader
+ Owen Leibman
+ 2010-09-02T20:48:39Z
+ 2010-09-02T20:48:39Z
+ PHPExcel Xml Reader Test Category
+ Maarten Balliauw
+ PHPExcel
+ https://github.com/PHPOffice/PhpSpreadsheet
+ 16.00
+
+
+ AbCd1234
+ 2019-01-31T07:00:00Z
+ 1
+ 3
+ 2
+ 3.14159
+
+
+
+
+
+ 8964
+ 23040
+ 32767
+ 32767
+ False
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Test String 1Test for a simple colour-formatted string |
+ 1 |
+ 5 |
+ A |
+ E |
+ 6 |
+ AE |
+
+
+ Test - String 2 |
+ 2 |
+ 6 |
+ B |
+ F |
+ 8 |
+ BF |
+ Dot |
+
+
+ Test #3 |
+ 3 |
+ 7 |
+ C |
+ G |
+ 10 |
+ CG |
+ Red |
+ Red |
+ Dash |
+
+
+ Test with (") in string |
+ 4 |
+ 8 |
+ D |
+ H |
+ 12 |
+ DH |
+ Orange |
+ Orange |
+ Dash/Dot/Dot |
+
+
+ 10 |
+ 26 |
+ 36 |
+ Yellow |
+ Yellow |
+ Dash/Dot |
+
+
+ Test #3 |
+ 1.23 |
+ 1 |
+ 1 |
+ 22 |
+ Green |
+ Green |
+ Thin Line |
+
+
+ Test #3 |
+ 2.34 |
+ 0 |
+ 0 |
+ 36 |
+ Blue |
+ Blue |
+ Thick Dash/Dot/Dot |
+
+
+ Test #3 |
+ 3.45 |
+ Purple |
+ Purple |
+ Variant Thick Dash/Dot/Dot |
+
+
+ Pink |
+ Pink |
+ Thick Dash/Dot |
+
+
+ 1960-12-19T00:00:00.000 |
+ TOP |
+ 0 |
+ Brown |
+ Brown |
+ Thick Dash |
+
+
+ 1.5 |
+ #DIV/0! |
+ Thick Line |
+
+
+ BOTTOM |
+ Extra Thick Line |
+
+
+ 1899-12-31T02:30:00.000 |
+ Мойва сушенаяTests for UTF-8 content |
+ Double Line |
+
+
+ LEFT |
+ Ärendetext |
+
+
+ 1960-12-19T01:30:00.000 |
+ Højde |
+
+
+ RIGHT |
+
+
+
+ BOX |
+ |
+ Test Column 1 |
+ |
+ |
+ |
+
+
+ |
+ Test Column 2 |
+ |
+ Patterned |
+ Patterned 2 |
+
+
+ |
+ |
+ Test Column 3 |
+
+
+ PhpSpreadsheet |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ Underline None |
+ |
+ Rotate 90 |
+ Rotate 45 |
+ Rotate -90 |
+ Rotate -45 |
+ |
+ |
+ |
+ |
+
+
+ Underline 1 |
+ Subscript |
+ |
+ |
+ |
+ |
+
+
+ Underline 2 |
+ Superscript |
+ |
+ |
+ |
+ |
+
+
+ Underline 3 |
+ |
+ |
+ |
+ |
+ |
+
+
+ Underline 4 |
+ |
+ |
+ |
+ |
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ I don't know if Gnumeric supports Rich Text in the same way as Excel, And this row should be autofit height with text wrap |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ Blue with underline |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ 5 |
+ 5 |
+ #NAME? |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ Hidden row above |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+ 600
+ 600
+
+
+ 3
+
+
+ 3
+ 18
+ 10
+
+
+ False
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ Heading 1 |
+ Heading 2 |
+ Third Heading |
+ Date Heading |
+ Time Heading |
+ Adjusted Date |
+ Adjusted Number |
+
+
+ ABC |
+ 1 |
+ 1.1100000000000001 |
+ 2001-01-01T00:00:00.000 |
+ 1899-12-31T01:00:00.000 |
+ 2000-12-31T00:00:00.000 |
+ 1.1100000000000001 |
+ A |
+ 1A |
+
+
+ BCD |
+ 2 |
+ 2.2200000000000002 |
+ 2002-02-02T00:00:00.000 |
+ 1899-12-31T02:00:00.000 |
+ 2002-01-31T00:00:00.000 |
+ 4.4400000000000004 |
+ B |
+ 2B |
+
+
+ CDE |
+ 3 |
+ 3.33 |
+ 2003-03-03T00:00:00.000 |
+ 1899-12-31T03:00:00.000 |
+ 2003-02-28T00:00:00.000 |
+ 9.99 |
+ C |
+ 3C |
+
+
+ DEF |
+ 4 |
+ 4.4400000000000004 |
+ 2004-04-03T23:00:00.000 |
+ 1899-12-31T04:00:00.000 |
+ 2004-03-30T23:00:00.000 |
+ 17.760000000000002 |
+ D |
+ 4D |
+
+
+ EFG |
+ 5 |
+ 5.55 |
+ 2005-05-04T23:00:00.000 |
+ 1899-12-31T05:00:00.000 |
+ 2005-04-29T23:00:00.000 |
+ 27.75 |
+ E |
+ 5E |
+
+
+ FGH |
+ 6 |
+ 6.66 |
+ 2006-06-05T23:00:00.000 |
+ 1899-12-31T06:00:00.000 |
+ 2006-05-30T23:00:00.000 |
+ 39.96 |
+ F |
+ 6F |
+
+
+ GHI |
+ 7 |
+ 7.77 |
+ 2007-07-06T23:00:00.000 |
+ 1899-12-31T07:00:00.000 |
+ 2007-06-29T23:00:00.000 |
+ 54.39 |
+ G |
+ 7G |
+
+
+ HIJ |
+ 8 |
+ 8.8800000000000008 |
+ 2008-08-07T23:00:00.000 |
+ 1899-12-31T08:00:00.000 |
+ 2008-07-30T23:00:00.000 |
+ 71.040000000000006 |
+ H |
+ 8H |
+
+
+ IJK |
+ 9 |
+ 9.99 |
+ 2009-09-08T23:00:00.000 |
+ 1899-12-31T09:00:00.000 |
+ 2009-08-30T23:00:00.000 |
+ 89.91 |
+ I |
+ 9I |
+
+
+ JKL |
+ 10 |
+ 11.1 |
+ 2010-10-09T23:00:00.000 |
+ 1899-12-31T10:00:00.000 |
+ 2010-09-29T23:00:00.000 |
+ 111 |
+ J |
+ 10J |
+
+
+ KLM |
+ 11 |
+ 12.21 |
+ 2011-11-11T00:00:00.000 |
+ 1899-12-31T11:00:00.000 |
+ 2011-10-31T00:00:00.000 |
+ 134.31 |
+ K |
+ 11K |
+
+
+ LMN |
+ 12 |
+ 13.32 |
+ 2012-12-12T00:00:00.000 |
+ 1900-01-12T00:00:00.000 |
+ 2012-11-30T00:00:00.000 |
+ 159.84 |
+ L |
+ 12L |
+
+
+ ZYX |
+ -1 |
+ -1.1100000000000001 |
+ 1999-12-01T00:00:00.000 |
+ 1899-12-31T23:00:00.000 |
+ 1999-12-02T00:00:00.000 |
+ 1.1100000000000001 |
+ M |
+ -1M |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ 600
+ 600
+
+
+
+ 3
+ 8
+ R1C9:R15C11
+
+
+ False
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php
index 6a526d027a..e4d251e28f 100644
--- a/src/PhpSpreadsheet/Reader/Xml.php
+++ b/src/PhpSpreadsheet/Reader/Xml.php
@@ -17,6 +17,8 @@
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
+use PhpOffice\PhpSpreadsheet\Style\Borders;
+use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Font;
use SimpleXMLElement;
@@ -32,13 +34,6 @@ class Xml extends BaseReader
*/
protected $styles = [];
- /**
- * Character set used in the file.
- *
- * @var string
- */
- protected $charSet = 'UTF-8';
-
/**
* Create a new Excel2003XML Reader instance.
*/
@@ -48,6 +43,56 @@ public function __construct()
$this->securityScanner = XmlScanner::getInstance($this);
}
+ private $fileContents = '';
+
+ private static $mappings = [
+ 'borderStyle' => [
+ '1continuous' => Border::BORDER_THIN,
+ '1dash' => Border::BORDER_DASHED,
+ '1dashdot' => Border::BORDER_DASHDOT,
+ '1dashdotdot' => Border::BORDER_DASHDOTDOT,
+ '1dot' => Border::BORDER_DOTTED,
+ '1double' => Border::BORDER_DOUBLE,
+ '2continuous' => Border::BORDER_MEDIUM,
+ '2dash' => Border::BORDER_MEDIUMDASHED,
+ '2dashdot' => Border::BORDER_MEDIUMDASHDOT,
+ '2dashdotdot' => Border::BORDER_MEDIUMDASHDOTDOT,
+ '2dot' => Border::BORDER_DOTTED,
+ '2double' => Border::BORDER_DOUBLE,
+ '3continuous' => Border::BORDER_THICK,
+ '3dash' => Border::BORDER_MEDIUMDASHED,
+ '3dashdot' => Border::BORDER_MEDIUMDASHDOT,
+ '3dashdotdot' => Border::BORDER_MEDIUMDASHDOTDOT,
+ '3dot' => Border::BORDER_DOTTED,
+ '3double' => Border::BORDER_DOUBLE,
+ ],
+ 'fillType' => [
+ 'solid' => Fill::FILL_SOLID,
+ 'gray75' => Fill::FILL_PATTERN_DARKGRAY,
+ 'gray50' => Fill::FILL_PATTERN_MEDIUMGRAY,
+ 'gray25' => Fill::FILL_PATTERN_LIGHTGRAY,
+ 'gray125' => Fill::FILL_PATTERN_GRAY125,
+ 'gray0625' => Fill::FILL_PATTERN_GRAY0625,
+ 'horzstripe' => Fill::FILL_PATTERN_DARKHORIZONTAL, // horizontal stripe
+ 'vertstripe' => Fill::FILL_PATTERN_DARKVERTICAL, // vertical stripe
+ 'reversediagstripe' => Fill::FILL_PATTERN_DARKUP, // reverse diagonal stripe
+ 'diagstripe' => Fill::FILL_PATTERN_DARKDOWN, // diagonal stripe
+ 'diagcross' => Fill::FILL_PATTERN_DARKGRID, // diagoanl crosshatch
+ 'thickdiagcross' => Fill::FILL_PATTERN_DARKTRELLIS, // thick diagonal crosshatch
+ 'thinhorzstripe' => Fill::FILL_PATTERN_LIGHTHORIZONTAL,
+ 'thinvertstripe' => Fill::FILL_PATTERN_LIGHTVERTICAL,
+ 'thinreversediagstripe' => Fill::FILL_PATTERN_LIGHTUP,
+ 'thindiagstripe' => Fill::FILL_PATTERN_LIGHTDOWN,
+ 'thinhorzcross' => Fill::FILL_PATTERN_LIGHTGRID, // thin horizontal crosshatch
+ 'thindiagcross' => Fill::FILL_PATTERN_LIGHTTRELLIS, // thin diagonal crosshatch
+ ],
+ ];
+
+ public static function xmlMappings(): array
+ {
+ return self::$mappings;
+ }
+
/**
* Can the current IReader read the file?
*
@@ -73,13 +118,10 @@ public function canRead($pFilename)
];
// Open file
- $this->openFile($pFilename);
- $fileHandle = $this->fileHandle;
+ $data = file_get_contents($pFilename);
- // Read sample data (first 2 KB will do)
- $data = fread($fileHandle, 2048);
- fclose($fileHandle);
- $data = str_replace("'", '"', $data); // fix headers with single quote
+ // Why?
+ //$data = str_replace("'", '"', $data); // fix headers with single quote
$valid = true;
foreach ($signature as $match) {
@@ -92,9 +134,14 @@ public function canRead($pFilename)
}
// Retrieve charset encoding
- if (preg_match('//um', $data, $matches)) {
- $this->charSet = strtoupper($matches[1]);
+ if (preg_match('//m', $data, $matches)) {
+ $charSet = strtoupper($matches[1]);
+ if (1 == preg_match('/^ISO-8859-\d[\dL]?$/i', $charSet)) {
+ $data = StringHelper::convertEncoding($data, 'UTF-8', $charSet);
+ $data = preg_replace('/()/um', '$1' . 'UTF-8' . '$2', $data, 1);
+ }
}
+ $this->fileContents = $data;
return $valid;
}
@@ -110,13 +157,14 @@ public function trySimpleXMLLoadString($pFilename)
{
try {
$xml = simplexml_load_string(
- $this->securityScanner->scan(file_get_contents($pFilename)),
+ $this->securityScanner->scan($this->fileContents ?: file_get_contents($pFilename)),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
} catch (\Exception $e) {
throw new Exception('Cannot load invalid XML file: ' . $pFilename, 0, $e);
}
+ $this->fileContents = '';
return $xml;
}
@@ -144,7 +192,7 @@ public function listWorksheetNames($pFilename)
$xml_ss = $xml->children($namespaces['ss']);
foreach ($xml_ss->Worksheet as $worksheet) {
$worksheet_ss = $worksheet->attributes($namespaces['ss']);
- $worksheetNames[] = self::convertStringEncoding((string) $worksheet_ss['Name'], $this->charSet);
+ $worksheetNames[] = (string) $worksheet_ss['Name'];
}
return $worksheetNames;
@@ -160,6 +208,9 @@ public function listWorksheetNames($pFilename)
public function listWorksheetInfo($pFilename)
{
File::assertFile($pFilename);
+ if (!$this->canRead($pFilename)) {
+ throw new Exception($pFilename . ' is an Invalid Spreadsheet file.');
+ }
$worksheetInfo = [];
@@ -179,10 +230,9 @@ public function listWorksheetInfo($pFilename)
$tmpInfo['totalRows'] = 0;
$tmpInfo['totalColumns'] = 0;
+ $tmpInfo['worksheetName'] = "Worksheet_{$worksheetID}";
if (isset($worksheet_ss['Name'])) {
$tmpInfo['worksheetName'] = (string) $worksheet_ss['Name'];
- } else {
- $tmpInfo['worksheetName'] = "Worksheet_{$worksheetID}";
}
if (isset($worksheet->Table->Row)) {
@@ -238,53 +288,23 @@ public function load($pFilename)
private static function identifyFixedStyleValue($styleList, &$styleAttributeValue)
{
+ $returnValue = false;
$styleAttributeValue = strtolower($styleAttributeValue);
foreach ($styleList as $style) {
if ($styleAttributeValue == strtolower($style)) {
$styleAttributeValue = $style;
+ $returnValue = true;
- return true;
+ break;
}
}
- return false;
- }
-
- /**
- * pixel units to excel width units(units of 1/256th of a character width).
- *
- * @param float $pxs
- *
- * @return float
- */
- protected static function pixel2WidthUnits($pxs)
- {
- $UNIT_OFFSET_MAP = [0, 36, 73, 109, 146, 182, 219];
-
- $widthUnits = 256 * ($pxs / 7);
- $widthUnits += $UNIT_OFFSET_MAP[($pxs % 7)];
-
- return $widthUnits;
- }
-
- /**
- * excel width units(units of 1/256th of a character width) to pixel units.
- *
- * @param float $widthUnits
- *
- * @return float
- */
- protected static function widthUnits2Pixel($widthUnits)
- {
- $pixels = ($widthUnits / 256) * 7;
- $offsetWidthUnits = $widthUnits % 256;
-
- return $pixels + round($offsetWidthUnits / (256 / 7));
+ return $returnValue;
}
protected static function hex2str($hex)
{
- return chr(hexdec($hex[1]));
+ return mb_chr((int) hexdec($hex[1]), 'UTF-8');
}
/**
@@ -308,51 +328,52 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
$docProps = $spreadsheet->getProperties();
if (isset($xml->DocumentProperties[0])) {
foreach ($xml->DocumentProperties[0] as $propertyName => $propertyValue) {
+ $stringValue = (string) $propertyValue;
switch ($propertyName) {
case 'Title':
- $docProps->setTitle(self::convertStringEncoding($propertyValue, $this->charSet));
+ $docProps->setTitle($stringValue);
break;
case 'Subject':
- $docProps->setSubject(self::convertStringEncoding($propertyValue, $this->charSet));
+ $docProps->setSubject($stringValue);
break;
case 'Author':
- $docProps->setCreator(self::convertStringEncoding($propertyValue, $this->charSet));
+ $docProps->setCreator($stringValue);
break;
case 'Created':
- $creationDate = strtotime($propertyValue);
+ $creationDate = strtotime($stringValue);
$docProps->setCreated($creationDate);
break;
case 'LastAuthor':
- $docProps->setLastModifiedBy(self::convertStringEncoding($propertyValue, $this->charSet));
+ $docProps->setLastModifiedBy($stringValue);
break;
case 'LastSaved':
- $lastSaveDate = strtotime($propertyValue);
+ $lastSaveDate = strtotime($stringValue);
$docProps->setModified($lastSaveDate);
break;
case 'Company':
- $docProps->setCompany(self::convertStringEncoding($propertyValue, $this->charSet));
+ $docProps->setCompany($stringValue);
break;
case 'Category':
- $docProps->setCategory(self::convertStringEncoding($propertyValue, $this->charSet));
+ $docProps->setCategory($stringValue);
break;
case 'Manager':
- $docProps->setManager(self::convertStringEncoding($propertyValue, $this->charSet));
+ $docProps->setManager($stringValue);
break;
case 'Keywords':
- $docProps->setKeywords(self::convertStringEncoding($propertyValue, $this->charSet));
+ $docProps->setKeywords($stringValue);
break;
case 'Description':
- $docProps->setDescription(self::convertStringEncoding($propertyValue, $this->charSet));
+ $docProps->setDescription($stringValue);
break;
}
@@ -361,7 +382,7 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
if (isset($xml->CustomDocumentProperties)) {
foreach ($xml->CustomDocumentProperties[0] as $propertyName => $propertyValue) {
$propertyAttributes = $propertyValue->attributes($namespaces['dt']);
- $propertyName = preg_replace_callback('/_x([0-9a-z]{4})_/', ['self', 'hex2str'], $propertyName);
+ $propertyName = preg_replace_callback('/_x([0-9a-f]{4})_/i', ['self', 'hex2str'], $propertyName);
$propertyType = Properties::PROPERTY_TYPE_UNKNOWN;
switch ((string) $propertyAttributes) {
case 'string':
@@ -413,7 +434,7 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
$spreadsheet->createSheet();
$spreadsheet->setActiveSheetIndex($worksheetID);
if (isset($worksheet_ss['Name'])) {
- $worksheetName = self::convertStringEncoding((string) $worksheet_ss['Name'], $this->charSet);
+ $worksheetName = (string) $worksheet_ss['Name'];
// Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in
// formula cells... during the load, all formulae should be correct, and we're simply bringing
// the worksheet name in line with the formula, not the reverse
@@ -476,7 +497,7 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
}
if (isset($cell_ss['HRef'])) {
- $spreadsheet->getActiveSheet()->getCell($cellRange)->getHyperlink()->setUrl($cell_ss['HRef']);
+ $spreadsheet->getActiveSheet()->getCell($cellRange)->getHyperlink()->setUrl((string) $cell_ss['HRef']);
}
if ((isset($cell_ss['MergeAcross'])) || (isset($cell_ss['MergeDown']))) {
@@ -493,14 +514,15 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
$spreadsheet->getActiveSheet()->mergeCells($cellRange);
}
- $cellIsSet = $hasCalculatedValue = false;
+ $hasCalculatedValue = false;
$cellDataFormula = '';
if (isset($cell_ss['Formula'])) {
$cellDataFormula = $cell_ss['Formula'];
$hasCalculatedValue = true;
}
if (isset($cell->Data)) {
- $cellValue = $cellData = $cell->Data;
+ $cellData = $cell->Data;
+ $cellValue = (string) $cellData;
$type = DataType::TYPE_NULL;
$cellData_ss = $cellData->attributes($namespaces['ss']);
if (isset($cellData_ss['Type'])) {
@@ -516,7 +538,6 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
const TYPE_ERROR = 'e';
*/
case 'String':
- $cellValue = self::convertStringEncoding($cellValue, $this->charSet);
$type = DataType::TYPE_STRING;
break;
@@ -540,6 +561,7 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
break;
case 'Error':
$type = DataType::TYPE_ERROR;
+ $hasCalculatedValue = false;
break;
}
@@ -555,7 +577,7 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
if ($hasCalculatedValue) {
$spreadsheet->getActiveSheet()->getCell($columnID . $rowID)->setCalculatedValue($cellValue);
}
- $cellIsSet = $rowHasData = true;
+ $rowHasData = true;
}
if (isset($cell->Comment)) {
@@ -566,15 +588,15 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
}
$node = $cell->Comment->Data->asXML();
$annotation = strip_tags($node);
- $spreadsheet->getActiveSheet()->getComment($columnID . $rowID)->setAuthor(self::convertStringEncoding($author, $this->charSet))->setText($this->parseRichText($annotation));
+ $spreadsheet->getActiveSheet()->getComment($columnID . $rowID)->setAuthor($author)->setText($this->parseRichText($annotation));
}
- if (($cellIsSet) && (isset($cell_ss['StyleID']))) {
+ if (isset($cell_ss['StyleID'])) {
$style = (string) $cell_ss['StyleID'];
if ((isset($this->styles[$style])) && (!empty($this->styles[$style]))) {
- if (!$spreadsheet->getActiveSheet()->cellExists($columnID . $rowID)) {
- $spreadsheet->getActiveSheet()->getCell($columnID . $rowID)->setValue(null);
- }
+ //if (!$spreadsheet->getActiveSheet()->cellExists($columnID . $rowID)) {
+ // $spreadsheet->getActiveSheet()->getCell($columnID . $rowID)->setValue(null);
+ //}
$spreadsheet->getActiveSheet()->getStyle($cellRange)->applyFromArray($this->styles[$style]);
}
}
@@ -622,20 +644,11 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
return $spreadsheet;
}
- protected static function convertStringEncoding($string, $charset)
- {
- if ($charset != 'UTF-8') {
- return StringHelper::convertEncoding($string, 'UTF-8', $charset);
- }
-
- return $string;
- }
-
protected function parseRichText($is)
{
$value = new RichText();
- $value->createText(self::convertStringEncoding($is, $this->charSet));
+ $value->createText($is);
return $value;
}
@@ -716,29 +729,41 @@ private function parseStyleAlignment($styleID, SimpleXMLElement $styleAttributes
case 'WrapText':
$this->styles[$styleID]['alignment']['wrapText'] = true;
+ break;
+ case 'Rotate':
+ $this->styles[$styleID]['alignment']['textRotation'] = $styleAttributeValue;
+
break;
}
}
}
+ private static $borderPositions = ['top', 'left', 'bottom', 'right'];
+
/**
* @param $styleID
*/
private function parseStyleBorders($styleID, SimpleXMLElement $styleData, array $namespaces): void
{
+ $diagonalDirection = '';
+ $borderPosition = '';
foreach ($styleData->Border as $borderStyle) {
$borderAttributes = $borderStyle->attributes($namespaces['ss']);
$thisBorder = [];
+ $style = (string) $borderAttributes->Weight;
+ $style .= strtolower((string) $borderAttributes->LineStyle);
+ $thisBorder['borderStyle'] = self::$mappings['borderStyle'][$style] ?? Border::BORDER_NONE;
foreach ($borderAttributes as $borderStyleKey => $borderStyleValue) {
switch ($borderStyleKey) {
- case 'LineStyle':
- $thisBorder['borderStyle'] = Border::BORDER_MEDIUM;
-
- break;
- case 'Weight':
- break;
case 'Position':
- $borderPosition = strtolower($borderStyleValue);
+ $borderStyleValue = strtolower((string) $borderStyleValue);
+ if (in_array($borderStyleValue, self::$borderPositions)) {
+ $borderPosition = $borderStyleValue;
+ } elseif ($borderStyleValue == 'diagonalleft') {
+ $diagonalDirection = $diagonalDirection ? Borders::DIAGONAL_BOTH : Borders::DIAGONAL_DOWN;
+ } elseif ($borderStyleValue == 'diagonalright') {
+ $diagonalDirection = $diagonalDirection ? Borders::DIAGONAL_BOTH : Borders::DIAGONAL_UP;
+ }
break;
case 'Color':
@@ -748,27 +773,45 @@ private function parseStyleBorders($styleID, SimpleXMLElement $styleData, array
break;
}
}
- if (!empty($thisBorder)) {
- if (($borderPosition == 'left') || ($borderPosition == 'right') || ($borderPosition == 'top') || ($borderPosition == 'bottom')) {
- $this->styles[$styleID]['borders'][$borderPosition] = $thisBorder;
- }
+ if ($borderPosition) {
+ $this->styles[$styleID]['borders'][$borderPosition] = $thisBorder;
+ } elseif ($diagonalDirection) {
+ $this->styles[$styleID]['borders']['diagonalDirection'] = $diagonalDirection;
+ $this->styles[$styleID]['borders']['diagonal'] = $thisBorder;
}
}
}
+ private static $underlineStyles = [
+ Font::UNDERLINE_NONE,
+ Font::UNDERLINE_DOUBLE,
+ Font::UNDERLINE_DOUBLEACCOUNTING,
+ Font::UNDERLINE_SINGLE,
+ Font::UNDERLINE_SINGLEACCOUNTING,
+ ];
+
+ private function parseStyleFontUnderline(string $styleID, string $styleAttributeValue): void
+ {
+ if (self::identifyFixedStyleValue(self::$underlineStyles, $styleAttributeValue)) {
+ $this->styles[$styleID]['font']['underline'] = $styleAttributeValue;
+ }
+ }
+
+ private function parseStyleFontVerticalAlign(string $styleID, string $styleAttributeValue): void
+ {
+ if ($styleAttributeValue == 'Superscript') {
+ $this->styles[$styleID]['font']['superscript'] = true;
+ }
+ if ($styleAttributeValue == 'Subscript') {
+ $this->styles[$styleID]['font']['subscript'] = true;
+ }
+ }
+
/**
* @param $styleID
*/
- private function parseStyleFont($styleID, SimpleXMLElement $styleAttributes): void
+ private function parseStyleFont(string $styleID, SimpleXMLElement $styleAttributes): void
{
- $underlineStyles = [
- Font::UNDERLINE_NONE,
- Font::UNDERLINE_DOUBLE,
- Font::UNDERLINE_DOUBLEACCOUNTING,
- Font::UNDERLINE_SINGLE,
- Font::UNDERLINE_SINGLEACCOUNTING,
- ];
-
foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
$styleAttributeValue = (string) $styleAttributeValue;
switch ($styleAttributeKey) {
@@ -793,9 +836,11 @@ private function parseStyleFont($styleID, SimpleXMLElement $styleAttributes): vo
break;
case 'Underline':
- if (self::identifyFixedStyleValue($underlineStyles, $styleAttributeValue)) {
- $this->styles[$styleID]['font']['underline'] = $styleAttributeValue;
- }
+ $this->parseStyleFontUnderline($styleID, $styleAttributeValue);
+
+ break;
+ case 'VerticalAlign':
+ $this->parseStyleFontVerticalAlign($styleID, $styleAttributeValue);
break;
}
@@ -810,11 +855,17 @@ private function parseStyleInterior($styleID, SimpleXMLElement $styleAttributes)
foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
switch ($styleAttributeKey) {
case 'Color':
- $this->styles[$styleID]['fill']['color']['rgb'] = substr($styleAttributeValue, 1);
+ $this->styles[$styleID]['fill']['endColor']['rgb'] = substr($styleAttributeValue, 1);
+ $this->styles[$styleID]['fill']['startColor']['rgb'] = substr($styleAttributeValue, 1);
+
+ break;
+ case 'PatternColor':
+ $this->styles[$styleID]['fill']['startColor']['rgb'] = substr($styleAttributeValue, 1);
break;
case 'Pattern':
- $this->styles[$styleID]['fill']['fillType'] = strtolower($styleAttributeValue);
+ $lcStyleAttributeValue = strtolower((string) $styleAttributeValue);
+ $this->styles[$styleID]['fill']['fillType'] = self::$mappings['fillType'][$lcStyleAttributeValue] ?? Fill::FILL_NONE;
break;
}
diff --git a/tests/PhpSpreadsheetTests/IOFactoryTest.php b/tests/PhpSpreadsheetTests/IOFactoryTest.php
index 906375bd26..f9512a3400 100644
--- a/tests/PhpSpreadsheetTests/IOFactoryTest.php
+++ b/tests/PhpSpreadsheetTests/IOFactoryTest.php
@@ -127,7 +127,9 @@ public function providerIdentify()
['samples/templates/30template.xls', 'Xls', Reader\Xls::class],
['samples/templates/OOCalcTest.ods', 'Ods', Reader\Ods::class],
['samples/templates/SylkTest.slk', 'Slk', Reader\Slk::class],
- ['samples/templates/Excel2003XMLTest.xml', 'Xml', Reader\Xml::class],
+ ['samples/templates/excel2003.xml', 'Xml', Reader\Xml::class],
+ // Following not readable by Excel.
+ //['samples/templates/Excel2003XMLTest.xml', 'Xml', Reader\Xml::class],
['samples/templates/46readHtml.html', 'Html', Reader\Html::class],
];
}
diff --git a/tests/PhpSpreadsheetTests/Reader/CsvTest.php b/tests/PhpSpreadsheetTests/Reader/CsvTest.php
index e11e0ff7b2..797f3f1deb 100644
--- a/tests/PhpSpreadsheetTests/Reader/CsvTest.php
+++ b/tests/PhpSpreadsheetTests/Reader/CsvTest.php
@@ -105,7 +105,7 @@ public function providerCanLoad()
{
return [
[false, 'tests/data/Reader/Ods/data.ods'],
- [false, 'tests/data/Reader/Xml/WithoutStyle.xml'],
+ [false, 'samples/templates/excel2003.xml'],
[true, 'tests/data/Reader/CSV/enclosure.csv'],
[true, 'tests/data/Reader/CSV/semicolon_separated.csv'],
[true, 'tests/data/Reader/CSV/contains_html.csv'],
diff --git a/tests/PhpSpreadsheetTests/Reader/Xml/XmlFilter.php b/tests/PhpSpreadsheetTests/Reader/Xml/XmlFilter.php
new file mode 100644
index 0000000000..1a20bb214d
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Reader/Xml/XmlFilter.php
@@ -0,0 +1,14 @@
+listWorksheetNames($filename);
+ self::assertCount(2, $names);
+ self::assertEquals('Sample Data', $names[0]);
+ self::assertEquals('Report Data', $names[1]);
+ }
+
+ public function testListNamesInvalidFile(): void
+ {
+ $this->expectException(ReaderException::class);
+ $filename = __FILE__;
+ $reader = new Xml();
+ $names = $reader->listWorksheetNames($filename);
+ self::assertNotEquals($names, $names);
+ }
+
+ public function testListInfo(): void
+ {
+ $filename = __DIR__
+ . '/../../../..'
+ . '/samples/templates/excel2003.xml';
+ $reader = new Xml();
+ $info = $reader->listWorksheetInfo($filename);
+ $expected = [
+ [
+ 'worksheetName' => 'Sample Data',
+ 'lastColumnLetter' => 'J',
+ 'lastColumnIndex' => 9,
+ 'totalRows' => 31,
+ 'totalColumns' => 10,
+ ],
+ [
+ 'worksheetName' => 'Report Data',
+ 'lastColumnLetter' => 'I',
+ 'lastColumnIndex' => 8,
+ 'totalRows' => 15,
+ 'totalColumns' => 9,
+ ],
+ ];
+ self::assertEquals($expected, $info);
+ }
+
+ public function testListInfoInvalidFile(): void
+ {
+ $this->expectException(ReaderException::class);
+ $filename = __FILE__;
+ $reader = new Xml();
+ $info = $reader->listWorksheetInfo($filename);
+ self::assertNotEquals($info, $info);
+ }
+
+ public function testLoadInvalidFile(): void
+ {
+ $this->expectException(ReaderException::class);
+ $filename = __FILE__;
+ $reader = new Xml();
+ $spreadsheet = $reader->load($filename);
+ self::assertNotEquals($spreadsheet, $spreadsheet);
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php b/tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php
new file mode 100644
index 0000000000..03f977f5f4
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php
@@ -0,0 +1,100 @@
+load($filename);
+ self::assertEquals(2, $spreadsheet->getSheetCount());
+
+ $sheet = $spreadsheet->getSheet(1);
+ self::assertEquals('Report Data', $sheet->getTitle());
+ self::assertEquals('BCD', $sheet->getCell('A4')->getValue());
+ $props = $spreadsheet->getProperties();
+ self::assertEquals('Mark Baker', $props->getCreator());
+ self::assertEquals('AbCd1234', $props->getCustomPropertyValue('my_API_Token'));
+ self::assertEquals('2', $props->getCustomPropertyValue('myאInt'));
+
+ $sheet = $spreadsheet->getSheet(0);
+ self::assertEquals('Sample Data', $sheet->getTitle());
+ self::assertEquals('Test String 1', $sheet->getCell('A1')->getValue());
+ self::assertEquals('Test with (") in string', $sheet->getCell('A4')->getValue());
+
+ self::assertEquals(22269, $sheet->getCell('A10')->getValue());
+ self::assertEquals('dd/mm/yyyy', $sheet->getCell('A10')->getStyle()->getNumberFormat()->getFormatCode());
+ self::assertEquals('19/12/1960', $sheet->getCell('A10')->getFormattedValue());
+ self::assertEquals(1.5, $sheet->getCell('A11')->getValue());
+ self::assertEquals('# ?0/??0', $sheet->getCell('A11')->getStyle()->getNumberFormat()->getFormatCode());
+ // Same pattern, same value, different display in Gnumeric vs Excel
+ //self::assertEquals('1 1/2', $sheet->getCell('A11')->getFormattedValue());
+
+ self::assertEquals('=B1+C1', $sheet->getCell('H1')->getValue());
+ self::assertEquals('=E2&F2', $sheet->getCell('J2')->getValue());
+ self::assertEquals('=SUM(C1:C4)', $sheet->getCell('I5')->getValue());
+
+ // property not yet supported
+ //self::assertFalse($sheet->getRowDimension(30)->getVisible());
+ $hyperlink = $sheet->getCell('A21');
+ self::assertEquals('PhpSpreadsheet', $hyperlink->getValue());
+ self::assertEquals('https://github.com/PHPOffice/PhpSpreadsheet', $hyperlink->getHyperlink()->getUrl());
+ }
+
+ public function testLoadFilter(): void
+ {
+ $filename = __DIR__
+ . '/../../../..'
+ . '/samples/templates/excel2003.xml';
+ $reader = new Xml();
+ $filter = new XmlFilter();
+ $reader->setReadFilter($filter);
+ $spreadsheet = $reader->load($filename);
+ self::assertEquals(2, $spreadsheet->getSheetCount());
+ $sheet = $spreadsheet->getSheet(1);
+ self::assertEquals('Report Data', $sheet->getTitle());
+ self::assertEquals('', $sheet->getCell('A4')->getValue());
+ $props = $spreadsheet->getProperties();
+ self::assertEquals('Mark Baker', $props->getCreator());
+ }
+
+ public function testLoadSelectedSheets(): void
+ {
+ $filename = __DIR__
+ . '/../../../..'
+ . '/samples/templates/excel2003.xml';
+ $reader = new Xml();
+ $reader->setLoadSheetsOnly(['Unknown Sheet', 'Report Data']);
+ $spreadsheet = $reader->load($filename);
+ self::assertEquals(1, $spreadsheet->getSheetCount());
+ $sheet = $spreadsheet->getSheet(0);
+ self::assertEquals('Report Data', $sheet->getTitle());
+ self::assertEquals('Third Heading', $sheet->getCell('C2')->getValue());
+ }
+
+ public function testLoadUnusableSample(): void
+ {
+ // Sample spreadsheet is not readable by Excel.
+ // But PhpSpreadsheet can load it except for coverage test.
+ //global $argv;
+ //if (in_array('--coverage-clover', $argv)) {
+ // self::markTestSkipped('Mysterious Travis coverage failure IOFactoryTest');
+ //}
+ $filename = __DIR__
+ . '/../../../..'
+ //. '/samples/templates/Excel2003XMLTest.xml';
+ . '/samples/templates/excel2003.short.bad.xml';
+ $reader = new Xml();
+ $spreadsheet = $reader->load($filename);
+ self::assertEquals(1, $spreadsheet->getSheetCount());
+ $sheet = $spreadsheet->getSheet(0);
+ self::assertEquals('Sample Data', $sheet->getTitle());
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Reader/Xml/XmlStyleCoverageTest.php b/tests/PhpSpreadsheetTests/Reader/Xml/XmlStyleCoverageTest.php
new file mode 100644
index 0000000000..970b3bc53b
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Reader/Xml/XmlStyleCoverageTest.php
@@ -0,0 +1,113 @@
+ $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");
+ }
+ }
+
+ /**
+ * @dataProvider providerfillType
+ */
+ public function testFillType(string $style, string $expectedResult): void
+ {
+ $styles = Xml::xmlMappings();
+ $borders = $styles['fillType'];
+ self::assertEquals($expectedResult, $borders[$style]);
+ }
+
+ public function testFillTypeCoverage(): void
+ {
+ $styles = Xml::XmlMappings();
+ $expected = $styles['fillType'];
+ $covered = [];
+ foreach ($expected as $key => $val) {
+ $covered[$key] = 0;
+ }
+ $tests = $this->providerfillType();
+ foreach ($tests as $test) {
+ $covered[$test[0]] = 1;
+ }
+ foreach ($covered as $key => $val) {
+ self::assertEquals(1, $val, "fillType $key not tested");
+ }
+ }
+
+ public function providerBorderStyle(): array
+ {
+ return [
+ ['1continuous', Border::BORDER_THIN],
+ ['1dash', Border::BORDER_DASHED],
+ ['1dashdot', Border::BORDER_DASHDOT],
+ ['1dashdotdot', Border::BORDER_DASHDOTDOT],
+ ['1dot', Border::BORDER_DOTTED],
+ ['1double', Border::BORDER_DOUBLE],
+ ['2continuous', Border::BORDER_MEDIUM],
+ ['2dash', Border::BORDER_MEDIUMDASHED],
+ ['2dashdot', Border::BORDER_MEDIUMDASHDOT],
+ ['2dashdotdot', Border::BORDER_MEDIUMDASHDOTDOT],
+ ['2dot', Border::BORDER_DOTTED],
+ ['2double', Border::BORDER_DOUBLE],
+ ['3continuous', Border::BORDER_THICK],
+ ['3dash', Border::BORDER_MEDIUMDASHED],
+ ['3dashdot', Border::BORDER_MEDIUMDASHDOT],
+ ['3dashdotdot', Border::BORDER_MEDIUMDASHDOTDOT],
+ ['3dot', Border::BORDER_DOTTED],
+ ['3double', Border::BORDER_DOUBLE],
+ ];
+ }
+
+ public function providerFillType(): array
+ {
+ return [
+ ['solid', Fill::FILL_SOLID],
+ ['gray75', Fill::FILL_PATTERN_DARKGRAY],
+ ['gray50', Fill::FILL_PATTERN_MEDIUMGRAY],
+ ['gray25', Fill::FILL_PATTERN_LIGHTGRAY],
+ ['gray125', Fill::FILL_PATTERN_GRAY125],
+ ['gray0625', Fill::FILL_PATTERN_GRAY0625],
+ ['horzstripe', Fill::FILL_PATTERN_DARKHORIZONTAL],
+ ['vertstripe', Fill::FILL_PATTERN_DARKVERTICAL],
+ ['reversediagstripe', Fill::FILL_PATTERN_DARKUP],
+ ['diagstripe', Fill::FILL_PATTERN_DARKDOWN],
+ ['diagcross', Fill::FILL_PATTERN_DARKGRID],
+ ['thickdiagcross', Fill::FILL_PATTERN_DARKTRELLIS],
+ ['thinhorzstripe', Fill::FILL_PATTERN_LIGHTHORIZONTAL],
+ ['thinvertstripe', Fill::FILL_PATTERN_LIGHTVERTICAL],
+ ['thinreversediagstripe', Fill::FILL_PATTERN_LIGHTUP],
+ ['thindiagstripe', Fill::FILL_PATTERN_LIGHTDOWN],
+ ['thinhorzcross', Fill::FILL_PATTERN_LIGHTGRID],
+ ['thindiagcross', Fill::FILL_PATTERN_LIGHTTRELLIS],
+ ];
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Reader/Xml/XmlStylesTest.php b/tests/PhpSpreadsheetTests/Reader/Xml/XmlStylesTest.php
new file mode 100644
index 0000000000..af5bfbc372
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Reader/Xml/XmlStylesTest.php
@@ -0,0 +1,135 @@
+load($filename);
+
+ $sheet = $spreadsheet->getSheet(0);
+ self::assertEquals(Border::BORDER_MEDIUM, $sheet->getCell('C10')->getStyle()->getBorders()->getTop()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C10')->getStyle()->getBorders()->getRight()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C10')->getStyle()->getBorders()->getBottom()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C10')->getStyle()->getBorders()->getLeft()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C12')->getStyle()->getBorders()->getTop()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C12')->getStyle()->getBorders()->getRight()->getBorderStyle());
+ self::assertEquals(Border::BORDER_MEDIUM, $sheet->getCell('C12')->getStyle()->getBorders()->getBottom()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C12')->getStyle()->getBorders()->getLeft()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C14')->getStyle()->getBorders()->getTop()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C14')->getStyle()->getBorders()->getRight()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C14')->getStyle()->getBorders()->getBottom()->getBorderStyle());
+ self::assertEquals(Border::BORDER_MEDIUM, $sheet->getCell('C14')->getStyle()->getBorders()->getLeft()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C16')->getStyle()->getBorders()->getTop()->getBorderStyle());
+ self::assertEquals(Border::BORDER_MEDIUM, $sheet->getCell('C16')->getStyle()->getBorders()->getRight()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C16')->getStyle()->getBorders()->getBottom()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C16')->getStyle()->getBorders()->getLeft()->getBorderStyle());
+ self::assertEquals(Border::BORDER_THICK, $sheet->getCell('C18')->getStyle()->getBorders()->getTop()->getBorderStyle());
+ self::assertEquals(Color::COLOR_RED, $sheet->getCell('C18')->getStyle()->getBorders()->getTop()->getColor()->getARGB());
+ self::assertEquals(Border::BORDER_THICK, $sheet->getCell('C18')->getStyle()->getBorders()->getRight()->getBorderStyle());
+ self::assertEquals(Color::COLOR_YELLOW, $sheet->getCell('C18')->getStyle()->getBorders()->getRight()->getColor()->getARGB());
+ self::assertEquals(Border::BORDER_THICK, $sheet->getCell('C18')->getStyle()->getBorders()->getRight()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C18')->getStyle()->getBorders()->getBottom()->getBorderStyle());
+ self::assertEquals(Border::BORDER_NONE, $sheet->getCell('C18')->getStyle()->getBorders()->getLeft()->getBorderStyle());
+
+ self::assertEquals(Borders::DIAGONAL_BOTH, $sheet->getCell('E18')->getStyle()->getBorders()->getDiagonalDirection());
+ self::assertEquals(Borders::DIAGONAL_DOWN, $sheet->getCell('I18')->getStyle()->getBorders()->getDiagonalDirection());
+ self::assertEquals(Borders::DIAGONAL_UP, $sheet->getCell('J18')->getStyle()->getBorders()->getDiagonalDirection());
+ }
+
+ public function testFont(): void
+ {
+ $filename = __DIR__
+ . '/../../../..'
+ . '/samples/templates/excel2003.xml';
+ $reader = new Xml();
+ $spreadsheet = $reader->load($filename);
+
+ $sheet = $spreadsheet->getSheet(0);
+ self::assertEquals('FFFF0000', $sheet->getCell('A1')->getStyle()->getFont()->getColor()->getARGB());
+ self::assertEquals(Font::UNDERLINE_SINGLE, $sheet->getCell('A3')->getStyle()->getFont()->getUnderline());
+
+ self::assertTrue($sheet->getCell('E1')->getStyle()->getFont()->getBold());
+ self::assertTrue($sheet->getCell('E1')->getStyle()->getFont()->getItalic());
+
+ self::assertFalse($sheet->getCell('E2')->getStyle()->getFont()->getBold());
+ self::assertFalse($sheet->getCell('E2')->getStyle()->getFont()->getItalic());
+ self::assertEquals(Font::UNDERLINE_NONE, $sheet->getCell('E2')->getStyle()->getFont()->getUnderline());
+ self::assertTrue($sheet->getCell('E3')->getStyle()->getFont()->getBold());
+ self::assertFalse($sheet->getCell('E3')->getStyle()->getFont()->getItalic());
+ self::assertEquals(Font::UNDERLINE_NONE, $sheet->getCell('E3')->getStyle()->getFont()->getUnderline());
+ self::assertFalse($sheet->getCell('E4')->getStyle()->getFont()->getBold());
+ self::assertTrue($sheet->getCell('E4')->getStyle()->getFont()->getItalic());
+ self::assertEquals(Font::UNDERLINE_NONE, $sheet->getCell('E4')->getStyle()->getFont()->getUnderline());
+
+ self::assertTrue($sheet->getCell('F1')->getStyle()->getFont()->getBold());
+ self::assertFalse($sheet->getCell('F1')->getStyle()->getFont()->getItalic());
+ self::assertEquals(Font::UNDERLINE_NONE, $sheet->getCell('F1')->getStyle()->getFont()->getUnderline());
+ self::assertFalse($sheet->getCell('F2')->getStyle()->getFont()->getBold());
+ self::assertFalse($sheet->getCell('F2')->getStyle()->getFont()->getItalic());
+ self::assertEquals(Font::UNDERLINE_NONE, $sheet->getCell('F2')->getStyle()->getFont()->getUnderline());
+ self::assertTrue($sheet->getCell('F3')->getStyle()->getFont()->getBold());
+ self::assertTrue($sheet->getCell('F3')->getStyle()->getFont()->getItalic());
+ self::assertEquals(Font::UNDERLINE_NONE, $sheet->getCell('F3')->getStyle()->getFont()->getUnderline());
+ self::assertFalse($sheet->getCell('F4')->getStyle()->getFont()->getBold());
+ self::assertFalse($sheet->getCell('F4')->getStyle()->getFont()->getItalic());
+ self::assertEquals(Font::UNDERLINE_NONE, $sheet->getCell('F4')->getStyle()->getFont()->getUnderline());
+
+ self::assertEquals(45, $sheet->getCell('E22')->getStyle()->getAlignment()->getTextRotation());
+ self::assertEquals(-90, $sheet->getCell('G22')->getStyle()->getAlignment()->getTextRotation());
+ self::assertEquals(Border::BORDER_DOUBLE, $sheet->getCell('N13')->getStyle()->getBorders()->getBottom()->getBorderStyle());
+
+ self::assertEquals(Font::UNDERLINE_DOUBLE, $sheet->getCell('A24')->getStyle()->getFont()->getUnderline());
+ self::assertTrue($sheet->getCell('B23')->getStyle()->getFont()->getSubScript());
+ self::assertTrue($sheet->getCell('B24')->getStyle()->getFont()->getSuperScript());
+ }
+
+ public function testFill(): void
+ {
+ $filename = __DIR__
+ . '/../../../..'
+ . '/samples/templates/excel2003.xml';
+ $reader = new Xml();
+ $spreadsheet = $reader->load($filename);
+
+ $sheet = $spreadsheet->getSheet(0);
+ self::assertEquals(Fill::FILL_PATTERN_DARKHORIZONTAL, $sheet->getCell('K19')->getStyle()->getFill()->getFillType());
+ self::assertEquals('FF00CCFF', $sheet->getCell('K19')->getStyle()->getFill()->getEndColor()->getARGB());
+ self::assertEquals(Color::COLOR_BLUE, $sheet->getCell('K19')->getStyle()->getFill()->getStartColor()->getARGB());
+ self::assertEquals(Fill::FILL_PATTERN_GRAY0625, $sheet->getCell('L19')->getStyle()->getFill()->getFillType());
+ self::assertEquals(Color::COLOR_RED, $sheet->getCell('L19')->getStyle()->getFill()->getEndColor()->getARGB());
+ self::assertEquals(Color::COLOR_YELLOW, $sheet->getCell('L19')->getStyle()->getFill()->getStartColor()->getARGB());
+ self::assertEquals(Fill::FILL_SOLID, $sheet->getCell('K3')->getStyle()->getFill()->getFillType());
+ self::assertEquals(Color::COLOR_RED, $sheet->getCell('K3')->getStyle()->getFill()->getEndColor()->getARGB());
+ }
+
+ public function testAlignment(): void
+ {
+ $filename = __DIR__
+ . '/../../../..'
+ . '/samples/templates/excel2003.xml';
+ $reader = new Xml();
+ $spreadsheet = $reader->load($filename);
+
+ $sheet = $spreadsheet->getSheet(0);
+ self::assertEquals(45, $sheet->getCell('E22')->getStyle()->getAlignment()->getTextRotation());
+ self::assertEquals(-90, $sheet->getCell('G22')->getStyle()->getAlignment()->getTextRotation());
+ self::assertEquals(Alignment::HORIZONTAL_CENTER, $sheet->getCell('N2')->getStyle()->getAlignment()->getHorizontal());
+ self::assertEquals(Alignment::HORIZONTAL_RIGHT, $sheet->getCell('N3')->getStyle()->getAlignment()->getHorizontal());
+ self::assertEquals(Alignment::VERTICAL_TOP, $sheet->getCell('K19')->getStyle()->getAlignment()->getVertical());
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Reader/XmlTest.php b/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php
similarity index 70%
rename from tests/PhpSpreadsheetTests/Reader/XmlTest.php
rename to tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php
index a8de877491..2b66c7b430 100644
--- a/tests/PhpSpreadsheetTests/Reader/XmlTest.php
+++ b/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php
@@ -1,6 +1,6 @@
load('samples/templates/Excel2003XMLTest.xml');
+ $spreadsheet = $reader->load('tests/data/Reader/Xml/excel2003.iso8859-1.xml');
$firstSheet = $spreadsheet->getSheet(0);
+ self::assertSame('Voilà', $spreadsheet->getActiveSheet()->getCell('A1')->getValue());
- $hyperlink = $firstSheet->getCell('L1');
+ $hyperlink = $firstSheet->getCell('A2');
self::assertEquals(DataType::TYPE_STRING, $hyperlink->getDataType());
self::assertEquals('PhpSpreadsheet', $hyperlink->getValue());
self::assertEquals('https://phpspreadsheet.readthedocs.io', $hyperlink->getHyperlink()->getUrl());
}
-
- public function testReadWithoutStyle(): void
- {
- $reader = new Xml();
- $spreadsheet = $reader->load('tests/data/Reader/Xml/WithoutStyle.xml');
- self::assertSame('Test String 1', $spreadsheet->getActiveSheet()->getCell('A1')->getValue());
- }
}
diff --git a/tests/data/Reader/Xml/excel2003.iso8859-1.xml b/tests/data/Reader/Xml/excel2003.iso8859-1.xml
new file mode 100644
index 0000000000..f63eb075c2
--- /dev/null
+++ b/tests/data/Reader/Xml/excel2003.iso8859-1.xml
@@ -0,0 +1,67 @@
+
+
+
+
+ Owen Leibman
+ Owen Leibman
+ 2020-06-20T18:12:18Z
+ 16.00
+
+
+
+
+
+ 8964
+ 23040
+ 32767
+ 32767
+ False
+ False
+
+
+
+
+
+
+
+
+ Voil |
+
+
+ PhpSpreadsheet |
+
+
+
+
+
+
+
+
+
+
+
+ 3
+ 2
+
+
+ False
+ False
+
+
+