tags:

views:

1711

answers:

4

I'm parsing XML results from an API call using PHP and xpath.

 $dom = new DOMDocument();
 $dom->loadXML($response->getBody());

 $xpath = new DOMXPath($dom);
 $xpath->registerNamespace("a", "http://www.example.com");

 $hrefs = $xpath->query('//a:Books/text()', $dom);

 for ($i = 0; $i < $hrefs->length; $i++) {
      $arrBookTitle[$i] = $hrefs->item($i)->data;
 }

 $hrefs = $xpath->query('//a:Books', $dom);

 for ($i = 0; $i < $hrefs->length; $i++) {
      $arrBookDewey[$i] = $hrefs->item($i)->getAttribute('DeweyDecimal');
 }

This works but is there a way I can access both the text and the attribute from one query? And if so how do you get to those items once query is executed?

A: 

Could you query for the concatenation?

$xpath->query('concat(//a:Books/text(), //a:Books/@DeweyDecimal)', $dom);

XSLT is an expression language in itself, and you can construct whatever specific format of return value you want from within the expression.

Greg Hewgill
Then would I just use the item->data and item->getAttribute to pull the results?
Scott Gottreu
I'm not sure how PHP's XSLT library works, but you might be able to get it with just item->data. It's worth a try, anyway.
Greg Hewgill
+3  A: 

After doing some looking around I came across this solution. This way I can get the element text and access any attributes of the node.

$hrefs = $xpath->query('//a:Books', $dom);

for ($i = 0; $i < $hrefs->length; $i++) {
    $arrBookTitle[$i] = $hrefs->item($i)->nodeValue;
    $arrBookDewey[$i] = $hrefs->item($i)->getAttribute('DeweyDecimal');
}
Scott Gottreu
+2  A: 

If your're just retrieving values from your XML document, SimpleXML might be the leaner, faster and memory-friendlier solution:

$xml=simplexml_load_string($response->getBody());
$xml->registerXPathNamespace('a', 'http://www.example.com');
$books=$xml->xpath('//a:Books');
foreach ($books as $i => $book) {
    $arrBookTitle[$i]=(string)$book;
    $arrBookDewey[$i]=$book['DeweyDecimal'];
}
Stefan Gehrig
+1  A: 

One single XPath expression that will select both the text nodes of "a:Books" and their "DeweyDecimal" attribute, is the following

//a:Books/text() | //a:Books/@DeweyDecimal

Do note the use of the XPath's union operator in the expression above.

Another note: try to avoid using the "//" abbreviation as it may cause the whole XML document to be traversed and thus is very expensive. It is recommended to use a more specific XPath expression (such as consisting of a chain of specific location steps) always when the structure of the XML document is known.

Dimitre Novatchev