Yonkee
Yonkee

Reputation: 1883

PHP - How to check for element each loop?

I am using the below loop to parse an XML file.

$link = $item->getElementsByTagName('link')->item(0)->firstChild->nodeValue;
$image = $item->getElementsByTagName('enclosure')->item(0)->getAttribute('url');

However, Some times the XML item doesn't have an 'enclosure' element and my entire page fails with the below error

PHP Fatal error:  Call to a member function getAttribute() on a non-object

How can I check for the element each loop and replace the $image variable with a static string if it doesn't exist?

Upvotes: 1

Views: 133

Answers (1)

hakre
hakre

Reputation: 197659

I suggest you use xpath for that. With DOMDocument and DOMXPath you can highly benefit from the DOMXPath::evaluate method as you can fetch string values directly. In case the element queried for does not exists, you'll get an empty string (you can also check existance with count() which returns 0 in case a node was not found).

Example:

$item  = $doc->getElementsByTagName('itme')->item(0);
$xpath = new DOMXPath($doc);

echo "link.....: ", $xpath->evaluate('string(.//link)', $item), "\n";
echo "enclosure: ", $xpath->evaluate('string(.//enclosure[@url])', $item), "\n";

I create some example XML

<feed-me>
    <item>
        <link>http://nytimes.com/2004/12/07FEST.html</link>
        <actor class="foo" xml:space="preserve"> </actor>
    </item>
</feed-me>

and the output is

link.....: http://nytimes.com/2004/12/07FEST.html
enclosure: 

As this example shows, the first xpath expression evaluated to the text-content of the <link> element. The second expression evalutes to an empty string because the attribute does not exists.

The problem that obtaining an attribute from a non-existing element as you have it when you access the objects in PHP code

$item->getElementsByTagName('enclosure')->item(0)->getAttribute('url');
                                             ^               ^
                                             |               |
                                   there is no item at       |
                                  index 0, this is NULL      |
                                                             |
                                                         NULL has no
                                                     getAttribute method
                                                        = FATAL ERROR

With the xpath expression on the other hand

 string(.//enclosure[@url])

the inner expression .//enclosure[@url] returns an empty nodelist and the string() function returns "" (empty string) for it. Otherwise it returns the string-value of the first node (that is in document order) within that nodelist.

All in all this makes it really easy to obtain the information from the document in a stable manner. You have to learn some little xpath language however. But we have it well supported here as well on Stackoverlow.

Example in full (and online demo to play around):

<?php
/**
 * PHP - How to check for element each loop?
 * @link http://stackoverflow.com/a/29452042/367456
 */

$buffer = <<<XML
<feed-me>
    <item>
        <link>http://nytimes.com/2004/12/07FEST.html</link>
        <actor class="foo" xml:space="preserve"> </actor>
    </item>
</feed-me>
XML;

$doc = new DOMDocument();
$doc->loadXML($buffer);
$xpath = new DOMXPath($doc);

$item = $doc->getElementsByTagName('itme')->item(0);

$xpath = new DOMXPath($doc);

echo "link.....: ", $xpath->evaluate('string(.//link)', $item), "\n";
echo "enclosure: ", $xpath->evaluate('string(.//enclosure[@url])', $item), "\n";

$item->getElementsByTagName('enclosure')->item(0)->getAttribute('url');

Upvotes: 2

Related Questions