Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call to getChildElements() makes the iteration skip steps #3

Open
greg0ire opened this issue Oct 8, 2014 · 8 comments
Open

Call to getChildElements() makes the iteration skip steps #3

greg0ire opened this issue Oct 8, 2014 · 8 comments
Labels

Comments

@greg0ire
Copy link
Contributor

greg0ire commented Oct 8, 2014

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 ?

@hakre
Copy link
Owner

hakre commented Oct 8, 2014

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.

@hakre hakre added the bug label Oct 8, 2014
@greg0ire
Copy link
Contributor Author

greg0ire commented Oct 8, 2014

Glad you could reproduce the issue, and thanks a lot for the workaround, I'll try that tomorrow.

@greg0ire greg0ire changed the title Call to getChildElements() makes the iteration skip steps ? Call to getChildElements() makes the iteration skip steps Oct 8, 2014
@hakre
Copy link
Owner

hakre commented Oct 8, 2014

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.

@greg0ire
Copy link
Contributor Author

greg0ire commented Oct 8, 2014

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.

@greg0ire
Copy link
Contributor Author

greg0ire commented Oct 9, 2014

The workaround works like a charm! Thanks again!

@hakre
Copy link
Owner

hakre commented Oct 9, 2014

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!

@jwundrak
Copy link
Contributor

@hakre, this issue can be closed, because it was resolved by 0.1.11 with skipNextRead-method and without this method in PR #21

@dearsina
Copy link

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants