src/XLSXParser/RowIterator.php
<?php declare(strict_types = 1); namespace Spaghetti\XLSXParser; use Iterator;use XMLReader; /** * @internal */final class RowIterator implements Iterator{ private const ROW = 'row'; private const ROW_INDEX = 'r'; private const COLUMN = 'c'; private const VALUE = 'v'; private const STYLE = 's'; private const TYPE = 't'; private ?Row $row = null; private XMLReader $xml; private array $currentValue; private bool $valid; private int $currentKey; private int $index; private readonly Transformer\Column $columnTransformer; private string $style; private string $type; public function __construct( private readonly Transformer\Value $valueTransformer, private readonly string $path, ?Transformer\Column $columnTransformer = null, ) { $this->columnTransformer = $columnTransformer ?? new Transformer\Column(); } public function current(): array { return $this->currentValue; } public function key(): int { return $this->currentKey; } public function next(): void { $this->valid = false; while ($this->xml->read()) { $this->processEndElement(); if ($this->valid) { return; } $this->process(); } } public function rewind(): void { $xml = new XMLReader(); $this->xml = false === $xml->open(uri: $this->path) ? null : $xml; $this->next(); } public function valid(): bool { return $this->valid; } private function processEndElement(): void { if (XMLReader::END_ELEMENT === $this->xml->nodeType) { $this->processEndValue(); } } private function processEndValue(): void { if (self::ROW === $this->xml->name) { $currentValue = $this->row?->getData(); if ([] !== $currentValue) { $this->currentValue = $currentValue; $this->valid = true; } } } private function process(): void { if (XMLReader::ELEMENT === $this->xml->nodeType) { match ($this->xml->name) { self::ROW => $this->processRow(), self::COLUMN => $this->processColumn(), self::VALUE => $this->processValue(), default => $this->processDefault(), }; } } private function processRow(): void { $this->currentKey = (int) $this->xml->getAttribute(name: self::ROW_INDEX); $this->row = new Row(); } private function processColumn(): void { $this->index = $this->columnTransformer->transform(name: $this->xml->getAttribute(name: self::ROW_INDEX)); $this->style = $this->xml->getAttribute(name: self::STYLE) ?? ''; $this->type = $this->xml->getAttribute(name: self::TYPE) ?? ''; } private function processValue(): void { $this->row?->addValue(columnIndex: $this->index, value: $this->valueTransformer->transform(value: $this->xml->readString(), type: $this->type, style: $this->style), ); } private function processDefault(): void { $this->row?->addValue(columnIndex: $this->index, value: $this->xml->readString()); }}