@@ -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}
0 commit comments