1

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?

2
  • $item is not object type that's why error is showing. Commented Apr 4, 2015 at 21:33
  • Use xpath instead, it's easier to deal with in case the result is empty. Commented Apr 4, 2015 at 21:51

1 Answer 1

2

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

2 Comments

Thanks for such a detailed answers. All working well now. Cheers.
Yours cheers, too. Read a bit in the manual about this new function in your tool-chest. It's especially good to know about the context-node for such parsing jobs in (foreach) loops.

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.