5

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?

4 Answers 4

4

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');
}
Sign up to request clarification or add additional context in comments.

Comments

3

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.

Comments

2

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

Comments

0

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.

2 Comments

Then would I just use the item->data and item->getAttribute to pull the results?
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.