Question

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?

Was it helpful?

Solution

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');
}

OTHER TIPS

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.

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'];
}

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top