Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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 readonly string $filePath;
22
 
23
    /** @var string Path of the sheet data XML file as in [Content_Types].xml */
24
    private readonly string $sheetDataXMLFilePath;
25
 
26
    /** @var XMLReader The XMLReader object that will help read sheet's XML data */
27
    private readonly XMLReader $xmlReader;
28
 
29
    /** @var XMLProcessor Helper Object to process XML nodes */
30
    private readonly 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
}