1 <?php 2 3 declare(strict_types=1); 4 5 namespace OpenSpout\Reader\XLSX; 6 7 use OpenSpout\Common\Exception\IOException; 8 use OpenSpout\Reader\Common\ColumnWidth; 9 use OpenSpout\Reader\Common\XMLProcessor; 10 use OpenSpout\Reader\Wrapper\XMLReader; 11 12 final class SheetHeaderReader 13 { 14 public const XML_NODE_COL = 'col'; 15 public const XML_NODE_SHEETDATA = 'sheetData'; 16 public const XML_ATTRIBUTE_MIN = 'min'; 17 public const XML_ATTRIBUTE_MAX = 'max'; 18 public const XML_ATTRIBUTE_WIDTH = 'width'; 19 20 /** @var string Path of the XLSX file being read */ 21 private string $filePath; 22 23 /** @var string Path of the sheet data XML file as in [Content_Types].xml */ 24 private string $sheetDataXMLFilePath; 25 26 /** @var XMLReader The XMLReader object that will help read sheet's XML data */ 27 private XMLReader $xmlReader; 28 29 /** @var XMLProcessor Helper Object to process XML nodes */ 30 private XMLProcessor $xmlProcessor; 31 32 /** @var ColumnWidth[] The widths of the columns in the sheet, if specified */ 33 private array $columnWidths = []; 34 35 /** 36 * @param string $filePath Path of the XLSX file being read 37 * @param string $sheetDataXMLFilePath Path of the sheet data XML file as in [Content_Types].xml 38 * @param XMLReader $xmlReader XML Reader 39 * @param XMLProcessor $xmlProcessor Helper to process XML files 40 */ 41 public function __construct( 42 string $filePath, 43 string $sheetDataXMLFilePath, 44 XMLReader $xmlReader, 45 XMLProcessor $xmlProcessor 46 ) { 47 $this->filePath = $filePath; 48 $this->sheetDataXMLFilePath = $this->normalizeSheetDataXMLFilePath($sheetDataXMLFilePath); 49 $this->xmlReader = $xmlReader; 50 51 // Register all callbacks to process different nodes when reading the XML file 52 $this->xmlProcessor = $xmlProcessor; 53 $this->xmlProcessor->registerCallback(self::XML_NODE_COL, XMLProcessor::NODE_TYPE_START, [$this, 'processColStartingNode']); 54 $this->xmlProcessor->registerCallback(self::XML_NODE_SHEETDATA, XMLProcessor::NODE_TYPE_START, [$this, 'processSheetDataStartingNode']); 55 56 // The reader should be unused, but we close to be sure 57 $this->xmlReader->close(); 58 59 if (false === $this->xmlReader->openFileInZip($this->filePath, $this->sheetDataXMLFilePath)) { 60 throw new IOException("Could not open \"{$this->sheetDataXMLFilePath}\"."); 61 } 62 63 // Now read the entire header of the sheet, until we reach the <sheetData> element 64 $this->xmlProcessor->readUntilStopped(); 65 66 // We don't need the reader anymore, so we close it 67 $this->xmlReader->close(); 68 } 69 70 /** 71 * @internal 72 * 73 * @return ColumnWidth[] 74 */ 75 public function getColumnWidths(): array 76 { 77 return $this->columnWidths; 78 } 79 80 /** 81 * @param XMLReader $xmlReader XMLReader object, positioned on a "<col>" starting node 82 * 83 * @return int A return code that indicates what action should the processor take next 84 */ 85 private function processColStartingNode(XMLReader $xmlReader): int 86 { 87 $min = (int) $xmlReader->getAttribute(self::XML_ATTRIBUTE_MIN); 88 $max = (int) $xmlReader->getAttribute(self::XML_ATTRIBUTE_MAX); 89 $width = (float) $xmlReader->getAttribute(self::XML_ATTRIBUTE_WIDTH); 90 91 \assert($min > 0); 92 \assert($max > 0); 93 94 $columnwidth = new ColumnWidth($min, $max, $width); 95 $this->columnWidths[] = $columnwidth; 96 97 return XMLProcessor::PROCESSING_CONTINUE; 98 } 99 100 /** 101 * @return int A return code that indicates what action should the processor take next 102 */ 103 private function processSheetDataStartingNode(): int 104 { 105 // The opening "<sheetData>" marks the end of the file 106 return XMLProcessor::PROCESSING_STOP; 107 } 108 109 /** 110 * @param string $sheetDataXMLFilePath Path of the sheet data XML file as in [Content_Types].xml 111 * 112 * @return string path of the XML file containing the sheet data, 113 * without the leading slash 114 */ 115 private function normalizeSheetDataXMLFilePath(string $sheetDataXMLFilePath): string 116 { 117 return ltrim($sheetDataXMLFilePath, '/'); 118 } 119 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body