2

I would like to loop through each book_list in the following xml file and for each book_list loop through each book for that book_list.

<inventory>
    <book_list>
        <book>
            <author>Rowling</author>
            <title>Harry Potter</title>
        </book>
        <book>
            <author>Blyton</author>
            <title>Famous 5</title>
        </book>
    </book_list>
    <book_list>
        <book>
            <author>Bloggs</author>
            <title>Learning XML</title>
        </book>
        <book>
            <author>Jones</author>
            <title>Beginning PHP</title>
        </book>
    </book_list>
</inventory>

How can I, for each book_list, loop through each book, using xpath in a php simplexml script? Here is my code,

$booklistpath = $xml->xpath('//booklist');

foreach ($booklistpath as $booklist) {
    $bookpath = $xml->xpath('//book');
    foreach ($bookpath as $book) {
        ...
    }
}

The first loop is fine, it goes through each book_list - but the nested loop, which is meant to go through each book for that particular book_list goes through each book in the entire document. I have also tried :-

'.//book'  and 
'descendant::book'
Rolando Isidoro
  • 4,983
  • 2
  • 31
  • 43
lorac
  • 23
  • 1
  • 4

1 Answers1

6

That's the right result since you're using the second xpath call on the original $xml which is the SimpleXMLElement for your whole XML document.

To get the books for each booklist just iterate them as follow:

$booklists = $sxe->xpath('//book_list');

foreach ($booklists as $booklist) {
    foreach ($booklist->book as $book) {
        echo $book->asXML();
    }
}
Rolando Isidoro
  • 4,983
  • 2
  • 31
  • 43
  • thanks for your help - any idea how to do this when there is a namespace? My real data has a namespace thus:- which would require foreach($booklist->ns:book as $book) { etc which causes a php parse error – lorac Apr 29 '13 at 16:28
  • Sure, use the **[SimpleXMLElement::registerXPathNamespace](http://php.net/manual/en/simplexmlelement.registerxpathnamespace.php)** function. Look at this to speed up things: http://stackoverflow.com/questions/595946/parse-xml-with-namespace-using-simplexml. – Rolando Isidoro Apr 29 '13 at 16:33
  • 2
    Namespaces are selected using the `->children()` method; in your example `foreach ( $booklist->children('ns', true)->book as $book )`. There is no need for XPath in this case, this is exactly what the SimpleXML access methods were made for. – IMSoP Apr 29 '13 at 19:47
  • @IMSoP, thanks for this clarification, I was getting xpath and SimpleXML mixed up, but all is working now. – lorac Apr 30 '13 at 09:57