If the contents of my XML file is:
<query>
<results/>
</query>
I'm using $obj = simplexml_load_file( $filepath )
so have the file contents stored in $obj
.
As you can see, the results tag is empty, it has no text or attributes.
How can I check if the results tag is empty?
I thought about doing this if ( empty( $obj->results ) )
but I don't think that's the right syntax.
As you can see, the results tag is empty, it has no text or attributes.
How can I check if the results tag is empty?
In XML an element is considered empty by definition if:
[Definition: An element with no content is said to be empty.] The representation of an empty element is either a start-tag immediately followed by an end-tag, or an empty-element tag. [Definition: An empty-element tag takes a special form:] [... it follows the definition of the empty-element tag with "/>" at then end]
So whether it is <results/>
or <results></results>
, in XML that is called an empty element. And note here that <results foo="bar"/>
also is an empty element. Important is the content of the element here, not the attributes.
So now in SimpleXML, how can you find out if an element has no content? It's actually pretty cumbersome. I would prefer to lean on the DOM sister library for that, then it's rather straight forward:
<?php
$buffer = <<<XML
<query>
<results/>
<results></results>
</query>
XML;
$xml = simplexml_load_string($buffer);
$element = $xml->results[0];
var_dump(dom_import_simplexml($element)->childNodes->length);
$element = $xml->results[1];
var_dump(dom_import_simplexml($element)->childNodes->length);
This example just parses the little XML document in $buffer
with SimpleXML into $xml
. Then the first and the second results
element is checked for the number of children via the DOM sister library of SimpleXML. If the number of children is zero, then the element is empty.
$isEmpty = !dom_import_simplexml($element)->childNodes->length;
With "pure" SimpleXML you've got a problem because of the limited model the simple in SimpleXML offers here. SimpleXML doesn't take comments into account for example and has problems accessing text-nodes if they are not leaf-nodes. You can (but must not as I've shown with DOM) work around with an xpath query around some of the limitations in SimpleXML. For example only match the element if it is not empty, so again a count of 0 signals an empty element:
var_dump(count($element->xpath('(.)[./node()]')));
The xpath here
(.)[./node()]
means: get only the current element if it has child-nodes. So query returns one element if not empty and zero elements if empty. This is one way to check for an empty element in SimpleXML. You can extend this principle to also check for attributes:
(.)[./node()|./@*]
Perhaps a bit cryptic. But to answer your question, that is the way to go:
$isEmpty = !count($element->xpath('(.)[./node()|./@*]'));
That is: empty XML element with zero attributes.
Hope this is helpful and sheds some light into areas you haven't explored so far.
Here is some example code sandbox style I created while writing the answer (try it online as well):
<?php
/**
* How to check if XML tag is empty using PHP?
* @link http://stackoverflow.com/a/29614074/367456
*/
$buffer = <<<XML
<query>
<results/>
<results afri="cloa<a"/>
<results><!-- help --></results>
<results><!-- help -->1<test>222</test></results>
</query>
XML;
$xml = simplexml_load_string($buffer);
$element = $xml->results[0];
// $path = '*';
// $path = '.';
// $path = 'self::*';
// $path = 'self::*[1]';
// $path = 'descendant::node()';
// $path = 'self::*[descendant::node()]';
// $path = '(.)[descendant::node()]';
// $path = '(.)[.//node()]';
// $path = '(.)[child::node()]';
$path = '(.)[./node()]';
$result = $element->xpath($path);
var_dump(count($result));
foreach ($result as $node) {
echo $node->asXML(), "\n";
}
echo "------\n";
var_dump(count($element->xpath('(.)[./node()]')));
var_dump(count($element->xpath('(.)[./node()|./@*]')));
var_dump(strlen($element) + $element->children()->count());
$element = $xml->results[1];
var_dump(dom_import_simplexml($element)->childNodes->length);
$dom = dom_import_simplexml($element);
$dom->appendChild($dom->ownerDocument->createTextNode(""));
var_dump($element->children()->count());