Skip to content

Commit b01f992

Browse files
author
Julian Wundrak
committed
Support read children without using "skipNextRead"
1 parent d32c987 commit b01f992

2 files changed

Lines changed: 44 additions & 3 deletions

File tree

src/XMLChildElementIterator.php

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ class XMLChildElementIterator extends XMLElementIterator
5353
*/
5454
private $name;
5555

56+
/**
57+
* @var int
58+
*/
59+
private $innerDepth;
60+
5661
/**
5762
* @inheritdoc
5863
*
@@ -81,6 +86,11 @@ public function rewind()
8186
!$this->moveToNextByNodeType(XMLReader::ELEMENT);
8287
}
8388

89+
// handles e.g. <parent/> -> no children available
90+
if ($this->reader->isEmptyElement) {
91+
return;
92+
}
93+
8494
if ($this->stopDepth === null) {
8595
$this->stopDepth = $this->reader->depth;
8696
}
@@ -89,6 +99,7 @@ public function rewind()
8999
$result = $this->nextChildElementByName($this->name);
90100

91101
$this->index = $result ? 0 : null;
102+
$this->innerDepth = 1;
92103
$this->didRewind = true;
93104
}
94105

@@ -160,15 +171,15 @@ private function nextChildElementByName($name = null)
160171
}
161172
}
162173

163-
return (bool)$next;
174+
return $next;
164175
}
165176

166177
/**
167178
* @return bool
168179
*/
169180
private function nextElement()
170181
{
171-
while ($this->reader->read()) {
182+
while ($this->readNext()) {
172183
if (XMLReader::ELEMENT !== $this->reader->nodeType) {
173184
continue;
174185
}
@@ -177,4 +188,28 @@ private function nextElement()
177188
}
178189
return false;
179190
}
191+
192+
/**
193+
* Wrap reading to track opening and closing tags to prevent reading not-children nodes
194+
*
195+
* @return bool
196+
*/
197+
protected function readNext()
198+
{
199+
// update inner depth
200+
if ($this->reader->nodeType === XMLReader::ELEMENT && !$this->reader->isEmptyElement) {
201+
$this->innerDepth++;
202+
} elseif ($this->reader->nodeType === XMLReader::END_ELEMENT) {
203+
$this->innerDepth--;
204+
205+
// all children read? Abort to prevent reading next node
206+
if ($this->innerDepth === 0) {
207+
// set pointer behind closing-tag
208+
parent::readNext();
209+
return false;
210+
}
211+
}
212+
213+
return parent::readNext();
214+
}
180215
}

src/XMLReaderIterator.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,17 @@ public function next()
167167
if ($this->skipNextRead) {
168168
$this->skipNextRead = false;
169169
$this->lastRead = $this->reader->nodeType !== XMLReader::NONE;
170-
} elseif ($this->lastRead = $this->reader->read() and $this->reader->nodeType === XMLReader::ELEMENT) {
170+
} elseif ($this->lastRead = $this->readNext() and $this->reader->nodeType === XMLReader::ELEMENT) {
171171
$this->touchElementStack();
172172
}
173173
}
174174

175+
#[\ReturnTypeWillChange]
176+
protected function readNext()
177+
{
178+
return $this->reader->read();
179+
}
180+
175181
/**
176182
* @return string
177183
* @since 0.0.19

0 commit comments

Comments
 (0)