Call to getChildElements() makes the iteration skip steps
I'm trying to read an xml file created with mysqldump --xml
The code looks like this :
<?php
$reader = new \XMLReader();
$reader->open($this->filename);
$objects = new \XMLElementIterator($reader, 'row');
foreach ($objects as $key => $row) {
echo 'importing row #' . ($key + 1) . PHP_EOL;
$this->importRow($row, $manager);
}
The importRow method loops over fields. It looks like this :
foreach ($row->getChildElements() as $field) {
$this->setValue(
$entity,
$field->getAttribute('name'),
(string) $field
);
}
When I comment out the importRow() call I get the right number of iterations. When I do not, I get half, and only entities with even ids get imported. It is as if the getChildElements() call would make the pointer increase.
Am I using the library wrong ?
Well, it is actually intended to work that way however, as I could reproduce your issue, it's broken. I'm working on a fix, but until then for your scenario, a working variant is to iterate the child elements via SimpleXMLElement:
foreach ($row->getSimpleXMLElement() as $field) {
$this->setValue(
$entity,
$field['name'],
(string) $field
);
}
This should work equally well for the moment. Let me know if you run into any issues with that.
Glad you could reproduce the issue, and thanks a lot for the workaround, I'll try that tomorrow.
well actually it's not really correct to say this is a flaw. getChildElements() is creating an XMLChildElementIterator that one iterates over all child elements then stops.
Because XMLReader is forward only, such a sub-iterator can not find out that it's done until it has moved on to the next (invalid) element.
In your case, that is the next <row> element of the outer iteration already. However as the outer iteration is an independent iterator on it's own and this is a foreach iteration, it moves on to the next <row> element as well. So one element is skipped per each iteration.
I have to check the invalidation decision for the child iterator here. it should be possible to stop at the closing tag. This should prevent the issue.
So both iterators are not so independent, if I get this correctly. They seem to share some kind of cursor, don't they ? Thanks for the explanations, it's very interesting.
The workaround works like a charm! Thanks again!
Well the "cursor" they share is XMLReader. I could not find time to fix that bug so far. Glad the alternative worked for you. Thank you for reporting this!
@hakre, this issue can be closed, because it was resolved by 0.1.11 with skipNextRead-method and without this method in PR #21
@jwundrak Can you please show me an example of how you can iterate over child (or grand child) nodes without it skipping the parent nodes using skipNextRead? Because I think this issue is still prevalent.