| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 | 
							- <?php
 
- namespace PhpOffice\PhpSpreadsheet\Reader;
 
- use DateTime;
 
- use DateTimeZone;
 
- use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
 
- use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
 
- use PhpOffice\PhpSpreadsheet\Cell\DataType;
 
- use PhpOffice\PhpSpreadsheet\Document\Properties;
 
- use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
 
- use PhpOffice\PhpSpreadsheet\RichText\RichText;
 
- use PhpOffice\PhpSpreadsheet\Settings;
 
- use PhpOffice\PhpSpreadsheet\Shared\Date;
 
- use PhpOffice\PhpSpreadsheet\Shared\File;
 
- use PhpOffice\PhpSpreadsheet\Spreadsheet;
 
- use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
 
- use XMLReader;
 
- use ZipArchive;
 
- class Ods extends BaseReader
 
- {
 
-     /**
 
-      * Create a new Ods Reader instance.
 
-      */
 
-     public function __construct()
 
-     {
 
-         $this->readFilter = new DefaultReadFilter();
 
-         $this->securityScanner = XmlScanner::getInstance($this);
 
-     }
 
-     /**
 
-      * Can the current IReader read the file?
 
-      *
 
-      * @param string $pFilename
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return bool
 
-      */
 
-     public function canRead($pFilename)
 
-     {
 
-         File::assertFile($pFilename);
 
-         $mimeType = 'UNKNOWN';
 
-         // Load file
 
-         $zip = new ZipArchive();
 
-         if ($zip->open($pFilename) === true) {
 
-             // check if it is an OOXML archive
 
-             $stat = $zip->statName('mimetype');
 
-             if ($stat && ($stat['size'] <= 255)) {
 
-                 $mimeType = $zip->getFromName($stat['name']);
 
-             } elseif ($stat = $zip->statName('META-INF/manifest.xml')) {
 
-                 $xml = simplexml_load_string(
 
-                     $this->securityScanner->scan($zip->getFromName('META-INF/manifest.xml')),
 
-                     'SimpleXMLElement',
 
-                     Settings::getLibXmlLoaderOptions()
 
-                 );
 
-                 $namespacesContent = $xml->getNamespaces(true);
 
-                 if (isset($namespacesContent['manifest'])) {
 
-                     $manifest = $xml->children($namespacesContent['manifest']);
 
-                     foreach ($manifest as $manifestDataSet) {
 
-                         $manifestAttributes = $manifestDataSet->attributes($namespacesContent['manifest']);
 
-                         if ($manifestAttributes->{'full-path'} == '/') {
 
-                             $mimeType = (string) $manifestAttributes->{'media-type'};
 
-                             break;
 
-                         }
 
-                     }
 
-                 }
 
-             }
 
-             $zip->close();
 
-             return $mimeType === 'application/vnd.oasis.opendocument.spreadsheet';
 
-         }
 
-         return false;
 
-     }
 
-     /**
 
-      * Reads names of the worksheets from a file, without parsing the whole file to a PhpSpreadsheet object.
 
-      *
 
-      * @param string $pFilename
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return string[]
 
-      */
 
-     public function listWorksheetNames($pFilename)
 
-     {
 
-         File::assertFile($pFilename);
 
-         $zip = new ZipArchive();
 
-         if (!$zip->open($pFilename)) {
 
-             throw new Exception('Could not open ' . $pFilename . ' for reading! Error opening file.');
 
-         }
 
-         $worksheetNames = [];
 
-         $xml = new XMLReader();
 
-         $xml->xml(
 
-             $this->securityScanner->scanFile('zip://' . realpath($pFilename) . '#content.xml'),
 
-             null,
 
-             Settings::getLibXmlLoaderOptions()
 
-         );
 
-         $xml->setParserProperty(2, true);
 
-         // Step into the first level of content of the XML
 
-         $xml->read();
 
-         while ($xml->read()) {
 
-             // Quickly jump through to the office:body node
 
-             while ($xml->name !== 'office:body') {
 
-                 if ($xml->isEmptyElement) {
 
-                     $xml->read();
 
-                 } else {
 
-                     $xml->next();
 
-                 }
 
-             }
 
-             // Now read each node until we find our first table:table node
 
-             while ($xml->read()) {
 
-                 if ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) {
 
-                     // Loop through each table:table node reading the table:name attribute for each worksheet name
 
-                     do {
 
-                         $worksheetNames[] = $xml->getAttribute('table:name');
 
-                         $xml->next();
 
-                     } while ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT);
 
-                 }
 
-             }
 
-         }
 
-         return $worksheetNames;
 
-     }
 
-     /**
 
-      * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
 
-      *
 
-      * @param string $pFilename
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return array
 
-      */
 
-     public function listWorksheetInfo($pFilename)
 
-     {
 
-         File::assertFile($pFilename);
 
-         $worksheetInfo = [];
 
-         $zip = new ZipArchive();
 
-         if (!$zip->open($pFilename)) {
 
-             throw new Exception('Could not open ' . $pFilename . ' for reading! Error opening file.');
 
-         }
 
-         $xml = new XMLReader();
 
-         $xml->xml(
 
-             $this->securityScanner->scanFile('zip://' . realpath($pFilename) . '#content.xml'),
 
-             null,
 
-             Settings::getLibXmlLoaderOptions()
 
-         );
 
-         $xml->setParserProperty(2, true);
 
-         // Step into the first level of content of the XML
 
-         $xml->read();
 
-         while ($xml->read()) {
 
-             // Quickly jump through to the office:body node
 
-             while ($xml->name !== 'office:body') {
 
-                 if ($xml->isEmptyElement) {
 
-                     $xml->read();
 
-                 } else {
 
-                     $xml->next();
 
-                 }
 
-             }
 
-             // Now read each node until we find our first table:table node
 
-             while ($xml->read()) {
 
-                 if ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) {
 
-                     $worksheetNames[] = $xml->getAttribute('table:name');
 
-                     $tmpInfo = [
 
-                         'worksheetName' => $xml->getAttribute('table:name'),
 
-                         'lastColumnLetter' => 'A',
 
-                         'lastColumnIndex' => 0,
 
-                         'totalRows' => 0,
 
-                         'totalColumns' => 0,
 
-                     ];
 
-                     // Loop through each child node of the table:table element reading
 
-                     $currCells = 0;
 
-                     do {
 
-                         $xml->read();
 
-                         if ($xml->name == 'table:table-row' && $xml->nodeType == XMLReader::ELEMENT) {
 
-                             $rowspan = $xml->getAttribute('table:number-rows-repeated');
 
-                             $rowspan = empty($rowspan) ? 1 : $rowspan;
 
-                             $tmpInfo['totalRows'] += $rowspan;
 
-                             $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
 
-                             $currCells = 0;
 
-                             // Step into the row
 
-                             $xml->read();
 
-                             do {
 
-                                 if ($xml->name == 'table:table-cell' && $xml->nodeType == XMLReader::ELEMENT) {
 
-                                     if (!$xml->isEmptyElement) {
 
-                                         ++$currCells;
 
-                                         $xml->next();
 
-                                     } else {
 
-                                         $xml->read();
 
-                                     }
 
-                                 } elseif ($xml->name == 'table:covered-table-cell' && $xml->nodeType == XMLReader::ELEMENT) {
 
-                                     $mergeSize = $xml->getAttribute('table:number-columns-repeated');
 
-                                     $currCells += (int) $mergeSize;
 
-                                     $xml->read();
 
-                                 } else {
 
-                                     $xml->read();
 
-                                 }
 
-                             } while ($xml->name != 'table:table-row');
 
-                         }
 
-                     } while ($xml->name != 'table:table');
 
-                     $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
 
-                     $tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1;
 
-                     $tmpInfo['lastColumnLetter'] = Coordinate::stringFromColumnIndex($tmpInfo['lastColumnIndex'] + 1);
 
-                     $worksheetInfo[] = $tmpInfo;
 
-                 }
 
-             }
 
-         }
 
-         return $worksheetInfo;
 
-     }
 
-     /**
 
-      * Loads PhpSpreadsheet from file.
 
-      *
 
-      * @param string $pFilename
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return Spreadsheet
 
-      */
 
-     public function load($pFilename)
 
-     {
 
-         // Create new Spreadsheet
 
-         $spreadsheet = new Spreadsheet();
 
-         // Load into this instance
 
-         return $this->loadIntoExisting($pFilename, $spreadsheet);
 
-     }
 
-     /**
 
-      * Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
 
-      *
 
-      * @param string $pFilename
 
-      * @param Spreadsheet $spreadsheet
 
-      *
 
-      * @throws Exception
 
-      *
 
-      * @return Spreadsheet
 
-      */
 
-     public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
 
-     {
 
-         File::assertFile($pFilename);
 
-         $timezoneObj = new DateTimeZone('Europe/London');
 
-         $GMT = new \DateTimeZone('UTC');
 
-         $zip = new ZipArchive();
 
-         if (!$zip->open($pFilename)) {
 
-             throw new Exception('Could not open ' . $pFilename . ' for reading! Error opening file.');
 
-         }
 
-         // Meta
 
-         $xml = simplexml_load_string(
 
-             $this->securityScanner->scan($zip->getFromName('meta.xml')),
 
-             'SimpleXMLElement',
 
-             Settings::getLibXmlLoaderOptions()
 
-         );
 
-         $namespacesMeta = $xml->getNamespaces(true);
 
-         $docProps = $spreadsheet->getProperties();
 
-         $officeProperty = $xml->children($namespacesMeta['office']);
 
-         foreach ($officeProperty as $officePropertyData) {
 
-             $officePropertyDC = [];
 
-             if (isset($namespacesMeta['dc'])) {
 
-                 $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']);
 
-             }
 
-             foreach ($officePropertyDC as $propertyName => $propertyValue) {
 
-                 $propertyValue = (string) $propertyValue;
 
-                 switch ($propertyName) {
 
-                     case 'title':
 
-                         $docProps->setTitle($propertyValue);
 
-                         break;
 
-                     case 'subject':
 
-                         $docProps->setSubject($propertyValue);
 
-                         break;
 
-                     case 'creator':
 
-                         $docProps->setCreator($propertyValue);
 
-                         $docProps->setLastModifiedBy($propertyValue);
 
-                         break;
 
-                     case 'date':
 
-                         $creationDate = strtotime($propertyValue);
 
-                         $docProps->setCreated($creationDate);
 
-                         $docProps->setModified($creationDate);
 
-                         break;
 
-                     case 'description':
 
-                         $docProps->setDescription($propertyValue);
 
-                         break;
 
-                 }
 
-             }
 
-             $officePropertyMeta = [];
 
-             if (isset($namespacesMeta['dc'])) {
 
-                 $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']);
 
-             }
 
-             foreach ($officePropertyMeta as $propertyName => $propertyValue) {
 
-                 $propertyValueAttributes = $propertyValue->attributes($namespacesMeta['meta']);
 
-                 $propertyValue = (string) $propertyValue;
 
-                 switch ($propertyName) {
 
-                     case 'initial-creator':
 
-                         $docProps->setCreator($propertyValue);
 
-                         break;
 
-                     case 'keyword':
 
-                         $docProps->setKeywords($propertyValue);
 
-                         break;
 
-                     case 'creation-date':
 
-                         $creationDate = strtotime($propertyValue);
 
-                         $docProps->setCreated($creationDate);
 
-                         break;
 
-                     case 'user-defined':
 
-                         $propertyValueType = Properties::PROPERTY_TYPE_STRING;
 
-                         foreach ($propertyValueAttributes as $key => $value) {
 
-                             if ($key == 'name') {
 
-                                 $propertyValueName = (string) $value;
 
-                             } elseif ($key == 'value-type') {
 
-                                 switch ($value) {
 
-                                     case 'date':
 
-                                         $propertyValue = Properties::convertProperty($propertyValue, 'date');
 
-                                         $propertyValueType = Properties::PROPERTY_TYPE_DATE;
 
-                                         break;
 
-                                     case 'boolean':
 
-                                         $propertyValue = Properties::convertProperty($propertyValue, 'bool');
 
-                                         $propertyValueType = Properties::PROPERTY_TYPE_BOOLEAN;
 
-                                         break;
 
-                                     case 'float':
 
-                                         $propertyValue = Properties::convertProperty($propertyValue, 'r4');
 
-                                         $propertyValueType = Properties::PROPERTY_TYPE_FLOAT;
 
-                                         break;
 
-                                     default:
 
-                                         $propertyValueType = Properties::PROPERTY_TYPE_STRING;
 
-                                 }
 
-                             }
 
-                         }
 
-                         $docProps->setCustomProperty($propertyValueName, $propertyValue, $propertyValueType);
 
-                         break;
 
-                 }
 
-             }
 
-         }
 
-         // Content
 
-         $dom = new \DOMDocument('1.01', 'UTF-8');
 
-         $dom->loadXML(
 
-             $this->securityScanner->scan($zip->getFromName('content.xml')),
 
-             Settings::getLibXmlLoaderOptions()
 
-         );
 
-         $officeNs = $dom->lookupNamespaceUri('office');
 
-         $tableNs = $dom->lookupNamespaceUri('table');
 
-         $textNs = $dom->lookupNamespaceUri('text');
 
-         $xlinkNs = $dom->lookupNamespaceUri('xlink');
 
-         $spreadsheets = $dom->getElementsByTagNameNS($officeNs, 'body')
 
-             ->item(0)
 
-             ->getElementsByTagNameNS($officeNs, 'spreadsheet');
 
-         foreach ($spreadsheets as $workbookData) {
 
-             /** @var \DOMElement $workbookData */
 
-             $tables = $workbookData->getElementsByTagNameNS($tableNs, 'table');
 
-             $worksheetID = 0;
 
-             foreach ($tables as $worksheetDataSet) {
 
-                 /** @var \DOMElement $worksheetDataSet */
 
-                 $worksheetName = $worksheetDataSet->getAttributeNS($tableNs, 'name');
 
-                 // Check loadSheetsOnly
 
-                 if (isset($this->loadSheetsOnly)
 
-                     && $worksheetName
 
-                     && !in_array($worksheetName, $this->loadSheetsOnly)) {
 
-                     continue;
 
-                 }
 
-                 // Create sheet
 
-                 if ($worksheetID > 0) {
 
-                     $spreadsheet->createSheet(); // First sheet is added by default
 
-                 }
 
-                 $spreadsheet->setActiveSheetIndex($worksheetID);
 
-                 if ($worksheetName) {
 
-                     // 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
 
-                     $spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false);
 
-                 }
 
-                 // Go through every child of table element
 
-                 $rowID = 1;
 
-                 foreach ($worksheetDataSet->childNodes as $childNode) {
 
-                     /** @var \DOMElement $childNode */
 
-                     // Filter elements which are not under the "table" ns
 
-                     if ($childNode->namespaceURI != $tableNs) {
 
-                         continue;
 
-                     }
 
-                     $key = $childNode->nodeName;
 
-                     // Remove ns from node name
 
-                     if (strpos($key, ':') !== false) {
 
-                         $keyChunks = explode(':', $key);
 
-                         $key = array_pop($keyChunks);
 
-                     }
 
-                     switch ($key) {
 
-                         case 'table-header-rows':
 
-                             /// TODO :: Figure this out. This is only a partial implementation I guess.
 
-                             //          ($rowData it's not used at all and I'm not sure that PHPExcel
 
-                             //          has an API for this)
 
- //                            foreach ($rowData as $keyRowData => $cellData) {
 
- //                                $rowData = $cellData;
 
- //                                break;
 
- //                            }
 
-                             break;
 
-                         case 'table-row':
 
-                             if ($childNode->hasAttributeNS($tableNs, 'number-rows-repeated')) {
 
-                                 $rowRepeats = $childNode->getAttributeNS($tableNs, 'number-rows-repeated');
 
-                             } else {
 
-                                 $rowRepeats = 1;
 
-                             }
 
-                             $columnID = 'A';
 
-                             foreach ($childNode->childNodes as $key => $cellData) {
 
-                                 // @var \DOMElement $cellData
 
-                                 if ($this->getReadFilter() !== null) {
 
-                                     if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) {
 
-                                         ++$columnID;
 
-                                         continue;
 
-                                     }
 
-                                 }
 
-                                 // Initialize variables
 
-                                 $formatting = $hyperlink = null;
 
-                                 $hasCalculatedValue = false;
 
-                                 $cellDataFormula = '';
 
-                                 if ($cellData->hasAttributeNS($tableNs, 'formula')) {
 
-                                     $cellDataFormula = $cellData->getAttributeNS($tableNs, 'formula');
 
-                                     $hasCalculatedValue = true;
 
-                                 }
 
-                                 // Annotations
 
-                                 $annotation = $cellData->getElementsByTagNameNS($officeNs, 'annotation');
 
-                                 if ($annotation->length > 0) {
 
-                                     $textNode = $annotation->item(0)->getElementsByTagNameNS($textNs, 'p');
 
-                                     if ($textNode->length > 0) {
 
-                                         $text = $this->scanElementForText($textNode->item(0));
 
-                                         $spreadsheet->getActiveSheet()
 
-                                             ->getComment($columnID . $rowID)
 
-                                             ->setText($this->parseRichText($text));
 
- //                                                                    ->setAuthor( $author )
 
-                                     }
 
-                                 }
 
-                                 // Content
 
-                                 /** @var \DOMElement[] $paragraphs */
 
-                                 $paragraphs = [];
 
-                                 foreach ($cellData->childNodes as $item) {
 
-                                     /** @var \DOMElement $item */
 
-                                     // Filter text:p elements
 
-                                     if ($item->nodeName == 'text:p') {
 
-                                         $paragraphs[] = $item;
 
-                                     }
 
-                                 }
 
-                                 if (count($paragraphs) > 0) {
 
-                                     // Consolidate if there are multiple p records (maybe with spans as well)
 
-                                     $dataArray = [];
 
-                                     // Text can have multiple text:p and within those, multiple text:span.
 
-                                     // text:p newlines, but text:span does not.
 
-                                     // Also, here we assume there is no text data is span fields are specified, since
 
-                                     // we have no way of knowing proper positioning anyway.
 
-                                     foreach ($paragraphs as $pData) {
 
-                                         $dataArray[] = $this->scanElementForText($pData);
 
-                                     }
 
-                                     $allCellDataText = implode($dataArray, "\n");
 
-                                     $type = $cellData->getAttributeNS($officeNs, 'value-type');
 
-                                     switch ($type) {
 
-                                         case 'string':
 
-                                             $type = DataType::TYPE_STRING;
 
-                                             $dataValue = $allCellDataText;
 
-                                             foreach ($paragraphs as $paragraph) {
 
-                                                 $link = $paragraph->getElementsByTagNameNS($textNs, 'a');
 
-                                                 if ($link->length > 0) {
 
-                                                     $hyperlink = $link->item(0)->getAttributeNS($xlinkNs, 'href');
 
-                                                 }
 
-                                             }
 
-                                             break;
 
-                                         case 'boolean':
 
-                                             $type = DataType::TYPE_BOOL;
 
-                                             $dataValue = ($allCellDataText == 'TRUE') ? true : false;
 
-                                             break;
 
-                                         case 'percentage':
 
-                                             $type = DataType::TYPE_NUMERIC;
 
-                                             $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value');
 
-                                             if (floor($dataValue) == $dataValue) {
 
-                                                 $dataValue = (int) $dataValue;
 
-                                             }
 
-                                             $formatting = NumberFormat::FORMAT_PERCENTAGE_00;
 
-                                             break;
 
-                                         case 'currency':
 
-                                             $type = DataType::TYPE_NUMERIC;
 
-                                             $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value');
 
-                                             if (floor($dataValue) == $dataValue) {
 
-                                                 $dataValue = (int) $dataValue;
 
-                                             }
 
-                                             $formatting = NumberFormat::FORMAT_CURRENCY_USD_SIMPLE;
 
-                                             break;
 
-                                         case 'float':
 
-                                             $type = DataType::TYPE_NUMERIC;
 
-                                             $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value');
 
-                                             if (floor($dataValue) == $dataValue) {
 
-                                                 if ($dataValue == (int) $dataValue) {
 
-                                                     $dataValue = (int) $dataValue;
 
-                                                 } else {
 
-                                                     $dataValue = (float) $dataValue;
 
-                                                 }
 
-                                             }
 
-                                             break;
 
-                                         case 'date':
 
-                                             $type = DataType::TYPE_NUMERIC;
 
-                                             $value = $cellData->getAttributeNS($officeNs, 'date-value');
 
-                                             $dateObj = new DateTime($value, $GMT);
 
-                                             $dateObj->setTimeZone($timezoneObj);
 
-                                             list($year, $month, $day, $hour, $minute, $second) = explode(
 
-                                                 ' ',
 
-                                                 $dateObj->format('Y m d H i s')
 
-                                             );
 
-                                             $dataValue = Date::formattedPHPToExcel(
 
-                                                 $year,
 
-                                                 $month,
 
-                                                 $day,
 
-                                                 $hour,
 
-                                                 $minute,
 
-                                                 $second
 
-                                             );
 
-                                             if ($dataValue != floor($dataValue)) {
 
-                                                 $formatting = NumberFormat::FORMAT_DATE_XLSX15
 
-                                                     . ' '
 
-                                                     . NumberFormat::FORMAT_DATE_TIME4;
 
-                                             } else {
 
-                                                 $formatting = NumberFormat::FORMAT_DATE_XLSX15;
 
-                                             }
 
-                                             break;
 
-                                         case 'time':
 
-                                             $type = DataType::TYPE_NUMERIC;
 
-                                             $timeValue = $cellData->getAttributeNS($officeNs, 'time-value');
 
-                                             $dataValue = Date::PHPToExcel(
 
-                                                 strtotime(
 
-                                                     '01-01-1970 ' . implode(':', sscanf($timeValue, 'PT%dH%dM%dS'))
 
-                                                 )
 
-                                             );
 
-                                             $formatting = NumberFormat::FORMAT_DATE_TIME4;
 
-                                             break;
 
-                                         default:
 
-                                             $dataValue = null;
 
-                                     }
 
-                                 } else {
 
-                                     $type = DataType::TYPE_NULL;
 
-                                     $dataValue = null;
 
-                                 }
 
-                                 if ($hasCalculatedValue) {
 
-                                     $type = DataType::TYPE_FORMULA;
 
-                                     $cellDataFormula = substr($cellDataFormula, strpos($cellDataFormula, ':=') + 1);
 
-                                     $temp = explode('"', $cellDataFormula);
 
-                                     $tKey = false;
 
-                                     foreach ($temp as &$value) {
 
-                                         // Only replace in alternate array entries (i.e. non-quoted blocks)
 
-                                         if ($tKey = !$tKey) {
 
-                                             // Cell range reference in another sheet
 
-                                             $value = preg_replace('/\[([^\.]+)\.([^\.]+):\.([^\.]+)\]/U', '$1!$2:$3', $value);
 
-                                             // Cell reference in another sheet
 
-                                             $value = preg_replace('/\[([^\.]+)\.([^\.]+)\]/U', '$1!$2', $value);
 
-                                             // Cell range reference
 
-                                             $value = preg_replace('/\[\.([^\.]+):\.([^\.]+)\]/U', '$1:$2', $value);
 
-                                             // Simple cell reference
 
-                                             $value = preg_replace('/\[\.([^\.]+)\]/U', '$1', $value);
 
-                                             $value = Calculation::translateSeparator(';', ',', $value, $inBraces);
 
-                                         }
 
-                                     }
 
-                                     unset($value);
 
-                                     // Then rebuild the formula string
 
-                                     $cellDataFormula = implode('"', $temp);
 
-                                 }
 
-                                 if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) {
 
-                                     $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated');
 
-                                 } else {
 
-                                     $colRepeats = 1;
 
-                                 }
 
-                                 if ($type !== null) {
 
-                                     for ($i = 0; $i < $colRepeats; ++$i) {
 
-                                         if ($i > 0) {
 
-                                             ++$columnID;
 
-                                         }
 
-                                         if ($type !== DataType::TYPE_NULL) {
 
-                                             for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) {
 
-                                                 $rID = $rowID + $rowAdjust;
 
-                                                 $cell = $spreadsheet->getActiveSheet()
 
-                                                     ->getCell($columnID . $rID);
 
-                                                 // Set value
 
-                                                 if ($hasCalculatedValue) {
 
-                                                     $cell->setValueExplicit($cellDataFormula, $type);
 
-                                                 } else {
 
-                                                     $cell->setValueExplicit($dataValue, $type);
 
-                                                 }
 
-                                                 if ($hasCalculatedValue) {
 
-                                                     $cell->setCalculatedValue($dataValue);
 
-                                                 }
 
-                                                 // Set other properties
 
-                                                 if ($formatting !== null) {
 
-                                                     $spreadsheet->getActiveSheet()
 
-                                                         ->getStyle($columnID . $rID)
 
-                                                         ->getNumberFormat()
 
-                                                         ->setFormatCode($formatting);
 
-                                                 } else {
 
-                                                     $spreadsheet->getActiveSheet()
 
-                                                         ->getStyle($columnID . $rID)
 
-                                                         ->getNumberFormat()
 
-                                                         ->setFormatCode(NumberFormat::FORMAT_GENERAL);
 
-                                                 }
 
-                                                 if ($hyperlink !== null) {
 
-                                                     $cell->getHyperlink()
 
-                                                         ->setUrl($hyperlink);
 
-                                                 }
 
-                                             }
 
-                                         }
 
-                                     }
 
-                                 }
 
-                                 // Merged cells
 
-                                 if ($cellData->hasAttributeNS($tableNs, 'number-columns-spanned')
 
-                                     || $cellData->hasAttributeNS($tableNs, 'number-rows-spanned')
 
-                                 ) {
 
-                                     if (($type !== DataType::TYPE_NULL) || (!$this->readDataOnly)) {
 
-                                         $columnTo = $columnID;
 
-                                         if ($cellData->hasAttributeNS($tableNs, 'number-columns-spanned')) {
 
-                                             $columnIndex = Coordinate::columnIndexFromString($columnID);
 
-                                             $columnIndex += (int) $cellData->getAttributeNS($tableNs, 'number-columns-spanned');
 
-                                             $columnIndex -= 2;
 
-                                             $columnTo = Coordinate::stringFromColumnIndex($columnIndex + 1);
 
-                                         }
 
-                                         $rowTo = $rowID;
 
-                                         if ($cellData->hasAttributeNS($tableNs, 'number-rows-spanned')) {
 
-                                             $rowTo = $rowTo + (int) $cellData->getAttributeNS($tableNs, 'number-rows-spanned') - 1;
 
-                                         }
 
-                                         $cellRange = $columnID . $rowID . ':' . $columnTo . $rowTo;
 
-                                         $spreadsheet->getActiveSheet()->mergeCells($cellRange);
 
-                                     }
 
-                                 }
 
-                                 ++$columnID;
 
-                             }
 
-                             $rowID += $rowRepeats;
 
-                             break;
 
-                     }
 
-                 }
 
-                 ++$worksheetID;
 
-             }
 
-         }
 
-         // Return
 
-         return $spreadsheet;
 
-     }
 
-     /**
 
-      * Recursively scan element.
 
-      *
 
-      * @param \DOMNode $element
 
-      *
 
-      * @return string
 
-      */
 
-     protected function scanElementForText(\DOMNode $element)
 
-     {
 
-         $str = '';
 
-         foreach ($element->childNodes as $child) {
 
-             /** @var \DOMNode $child */
 
-             if ($child->nodeType == XML_TEXT_NODE) {
 
-                 $str .= $child->nodeValue;
 
-             } elseif ($child->nodeType == XML_ELEMENT_NODE && $child->nodeName == 'text:s') {
 
-                 // It's a space
 
-                 // Multiple spaces?
 
-                 /** @var \DOMAttr $cAttr */
 
-                 $cAttr = $child->attributes->getNamedItem('c');
 
-                 if ($cAttr) {
 
-                     $multiplier = (int) $cAttr->nodeValue;
 
-                 } else {
 
-                     $multiplier = 1;
 
-                 }
 
-                 $str .= str_repeat(' ', $multiplier);
 
-             }
 
-             if ($child->hasChildNodes()) {
 
-                 $str .= $this->scanElementForText($child);
 
-             }
 
-         }
 
-         return $str;
 
-     }
 
-     /**
 
-      * @param string $is
 
-      *
 
-      * @return RichText
 
-      */
 
-     private function parseRichText($is)
 
-     {
 
-         $value = new RichText();
 
-         $value->createText($is);
 
-         return $value;
 
-     }
 
- }
 
 
  |