knightly

Blog Archives

PHP5 SimpleXML and xpath

Yesterday when working with some rather large XML files i noticed. That it’s not possible to do ->xpath() calls on sub nodes of a SimpleXMLElement. If that’s not clear. Here is a small example.

$xmlStr = '<root>
	<fareOption>
		<fare>
			<flight></flight>
			<flight></flight>
			<flight></flight>
		</fare>
	</fareOption>
	<fareOption>
		<fare>
			<flight></flight>
			<flight></flight>
			<flight></flight>
		</fare>
	</fareOption>
</root>';

$objXML = simplexml_load_string($xmlStr);
$fareList = $objXML->xpath('//fareOption');

foreach ($fareList as $fare) {
    $flightList = $fare->xpath('//flight');
    print_r($flightList);
}

So first i try to get all the fareOption elements from the XML structure. And loop through the extracted elements. In the loop i want to do a ->xpath call on $fare which is a instance of SimpleXMLElement. The result however is not what i expected. Instead of extracting all the flights of a $fare node. It extracts all flights from the root of the document. So instead of 3 flight nodes i get 6.

I couldn’t really find a solution for this problem. And from reading some bug reports i understand this is how the PHP implementation of xpath works at the moment. To solve this problem. There is a small work around though. Instead of running the ->xpath() call on the $fare node directly. We can create a new SimpleXMLElement from the $fare node. And do a ->xpath() call on that. This will look something like this.

foreach ($fareList as $fare) {
    $tempList = simplexml_load_string($fare->asXML());
    $flightList = $tempList->xpath('//flight');
    print_r($flightList);
}

This creates the expected output.