3

If I have some XML, for example:

<library>
    <books>
        <book>
            <title>book #1</title>
        </book>
        <book>
            <title>book #2</title>
        </book>
    </books>
    <authors>
         <author>
             <name>author #1</name>
         </author>
         <author>
             <name>author #2</name>
         </author>
    </authors>
</library>

And having manoeuvred my cursor to the first book element I loop using:

do {
    //...
} while($xml->next("book"));

When my cursor is on the last book element and the next("book") is called, what happens to the cursor?

  • Does it stay on the last book element and return false.
  • Does it move to the </library> and return false.
  • Does it do something else?

I cannot figure out how to get the current cursor position to figure this out for myself.

BudgieInWA
  • 2,184
  • 1
  • 17
  • 31

2 Answers2

4

Having looked at the source code of that function: http://lxr.php.net/xref/PHP_5_4/ext/xmlreader/php_xmlreader.c#821

It would appear that pointer moves to the end of the XML.

3

XMLReader::next() moves to the next node by skipping all subtree nodes. That is, it goes to the next node that has the same or lower XMLReader::$depth as the current one. If there is no next elment-node (after the end of document), the reader stops going to the next node.

In your case you specify a local-name with the parameter, in such a case, it will not take all of those matching next nodes, but only those, that are an element-node with the local-name given in the parameter.

When my cursor is on the last book element and the next("book") is called, what happens to the cursor?

  cursor is currently here
            |
            v
            <book>
                <title>book #2</title>
            </book>
        </books>
        <authors>
             <author>
                 <name>author #1</name>
             </author>
             <author>
                 <name>author #2</name>
             </author>
        </authors>
    </library>

From the current cursor position, next('book') would not find any other element-node with the local-name "book" in the document (skipping subtree nodes) before reaching the end of document. So it will be at the end of document. XMLReader::$nodeType is XMLReader::NONE then, and XMLReader::$depth is 0.

So in your case, it moves to the end of the document.

  • Does it stay on the last book element and return false.

No, it does not stay. That is for two reasons: First, you called next() which commands to move on. So the cursor location is expected to change. Second, XMLReader does not keep much state. It only knows current. There is not something like last or first. There is only current. The node-type of current is XMLReader::$nodeType. If it is XMLReader::NONE you either just opened (beginning of file) or you consumed the whole document (end of file).

  • Does it move to the </library> and return false.

No, it does not move to </library>. That is because you used next() with the local-name parameter. It would have moved there without the parameter (just $xml->next() multiple times), however as that operation would have been successful, it would have returned true then.

  • Does it do something else?

Yes, it merely does what I wrote above and what is documented in the XMLReader::next() PHP manual page.

I cannot figure out how to get the current cursor position to figure this out for myself.

As XMLReader only knows current there is not much of a cursor position maintained. XMLReader is forward-only on elements, there is only limited movement within the opening tag of an element, to read the attributes and then jumping "back" to the element.

For information about the current node, there is the ->nodeType field, as well as the ->depth field.

Additionally you can visualize the node at the cursor be ->expand()ing it and import it into a DOMDocument to save it as XML. However in your case you're after the end of the document, so you can not expand any longer. Check with the ->nodeType field first then.

I also have in my XMLReaderIterator library on github some dump function that can be useful to debug nodes and structure (XMLReaderNode::dump()).

You also might find the iterators there useful in using XMLReader, for example there is one that iterates only over children and stops when done.

hakre
  • 193,403
  • 52
  • 435
  • 836