php SimpleXML check if a child exists

A->b->c might exist but c might not exist. How do I check it?

13.10.2009 15:04:04
Please select a new answer
Tim Ogilvy 27.04.2017 09:58:30
15 ОТВЕТОВ
РЕШЕНИЕ
if($A->b->c != null) //c exists

If c does not exist, its value will be null (or, to be more precise, it will have no value). Note, however, that for this to work, both A and b need to not be null. Otherwise, PHP will throw an error (I think).

-19
15.11.2016 15:20:35
This isn't a great idea. c will be an empty object if the node does not exist, which isn't the same as NULL.
spikyjt 22.01.2013 11:15:01
To add to what @spikyjt said, if node c doesn't exist in $A->b, an empty SimpleXMLElement is returned. The valid instance of SimpleXMLElement is not null; that expression always evaluates true.
Matt 19.11.2013 19:17:39

It might be better to wrap this in an isset()

if(isset($A->b->c)) { // c exists

That way if $A or $A->b don't exist... it doesn't blow up.

122
13.10.2009 18:41:21
This seemed neater than the other answers, but actually SimpleXMLElement returns and empty SimpleXMLElement object for any requested node that doesn't exist. So the empty() method seems like the best route.
spikyjt 22.01.2013 11:22:58
also, c may be optional but A and b may be required, so I may actually want to get an exception if they are not defined - easy way to check document's integrity
davka 28.02.2013 10:50:00
@spikyjt isset() is the best route to check if the node exists. You can use empty() if you need to check whether the node exists AND has something inside it, i.e. between > and < (either text or child nodes). If you need just to check for the existence of the node then empty() won't do. For example, empty() will return you true for this node <b a="zzz"></b>
CITBL 18.04.2017 15:42:18
@CITBL you are correct, empty() is not much use. It is important to be aware however, that if there is no c element, isset($A->c) === false, but $A->c returns an empty SimpleXMLElement. So with $c = $A->c;, then isset($c) === true (i.e. $c !== null even though that might be expected).
spikyjt 18.04.2017 22:14:44

I solved it by using the children() function and doing a count() on it, ignoring an PHP error if there are no children by putting an @ before the count-call. This is stupid, but it works:

$identification = $xml->identification;
if (@count($identification->children()) == 0)
  $identification = $xml->Identification;

I hate this...

8
13.09.2011 18:09:35
Ignoring errors and warnings is very bad.
schellingerht 27.01.2020 05:49:33
You are completely right (that's why I said 'I hate this...'), but when you know that whatever error happens, you want it to be ignored, then this is fine.
scippie 28.01.2020 08:10:53

SimpleXML always return Object. If there is no child, empty object is returned.

if( !empty($a->b)){
  var_dump($a->b);
}
40
17.03.2011 20:03:04
Apparently this is a feature and not a bug. And it is very important to note this. Accessing a child of the object will create it if it does not exist.
cosmin 25.04.2013 14:50:24
This should be the accepted answer, would have saved me some time and frustration :-)
Niek Klein Kromhof 24.05.2016 14:09:58
Wrong answer. Because empty() returns true even if the node exists but has no content. For example, in your code sample, if $a contains this: <xml><b a="zzz"/></xml> then empty($a->b) will return true. Therefore that's not a reliable way to check if a node exists. You can use empty() though if you need something inside a node, i.e. between > and <, and not interested in the node without content
CITBL 28.04.2017 20:04:13

If you have PHP 5.3, you can just use $a->count(). Otherwise, scippie's solution using @count($a->children()) works well. I find I don't need the @ but older PHP implementations may need it.

4
13.09.2011 18:09:53
This should be the accepted answer, the currently accepted one is wrong.
Robbert van den Bogerd 20.12.2018 12:48:04

You could try:

if($A->b->c && $A->b->c != '')
0
13.09.2011 18:09:00

Using if(isset($A->b){ gave me issues, so I tried if($A->b){ and it worked!

2
6.06.2012 12:49:51
count and cast to boolean are the two ways that makes sense. Using if as you describe is the shortest way to cast to boolean.
Brilliand 6.01.2015 18:56:58

Thought I'd share my experience. Running on 5.4 I tried testing with 'isset' and 'empty' but neither worked for me. I ended up using is_null.

if(!is_null($xml->scheduler->outterList->innerList)) {
    //do something
}
0
2.08.2013 21:29:59

Method xpath returns array of matched elements or false

if(false !== $A->xpath('b/c')) { ...

http://www.php.net/manual/ru/simplexmlelement.xpath.php

5
25.09.2013 10:32:06
No, the docs indicate it returns FALSE if there's an error, not if the path returned no results.
Brian 14.03.2017 15:24:33
Tested this, @Brian is correct, it will only return false when an error occurs. Do not use this check, it will always return a (empty) node.
Robbert van den Bogerd 20.12.2018 12:46:01

After some experimentation, I've discovered that the only reliable method of checking if a node exists is using count($xml->someNode).

Here's a test case: https://gist.github.com/Thinkscape/6262156

8
10.04.2014 12:52:08

Name Spaces

Be aware that if you are using name spaces in your XML file you will need to include those in your function calls when checking for children otherwise it will return ZERO every time:

if ($XMLelement->children($nameSpace,TRUE)->count()){
    //do something here 
}
0
1.10.2014 17:26:55

The 3 ways I can confirm work in PHP 5.5.23 were using isset() count() or empty()

Here is a script to show the results from each:

https://gist.github.com/mchelen/306f4f31f21c02cb0c24

1
15.04.2015 18:43:09

Simply

var_dump(count($xml->node));
3
15.03.2017 18:04:28
In PHP7.2 they added a warning when counting something that does not implement Countable interface. So, this should be taken into account and better use isset() over count()
shirkkan 18.02.2019 08:48:52

Using xpath:

function has_child(\SimpleXMLElement $parent=null, string $xpathToChild)
{
    return isset($parent) && !empty($parent->xpath('('.$xpathToChild.')[1]'));
}

where $parent is an indirect or direct parent of the child node to check and $xpathToChild is an xpath of the child relative to $parent.

()[1] is because we don't want to select all the child nodes. One is enough.

To check if $a->b->c exists:

has_child($a,'b/c');

You can also check for attributes. To check if the node c has the t attribute.

has_child($a,'b/c/@t');
2
21.12.2018 19:19:17

I use a helper function to check if a node is a valid node provided as a parameter in function.

private static function isValidNode($node) {
  return isset($node) && $node instanceof SimpleXMLElement && !empty($node);
}

Usage example:

public function getIdFromNode($node) {
  if (!self::isValidNode($node)) {
    return 0;
  }
  return (int)$node['id'];
}
1
7.06.2018 13:27:23