使用PHP的SimpleXML检测空XML节点

Let me start by saying I'm not well versed in parsing XML and/or writing PHP. I've been researching and piecing things together for what I'm working on, but I'm stuck.

I'm trying to create a basic if/else statement: if the node isn't empty, write the content of the node.

Here's a snippet of the XML I'm calling:

<channel>
    <item>
      <title>This is a test</title>
      <link />
      <description>Test description</description>
      <category>Test category</category>
      <guid />
    </item>
  </channel>

and here's the PHP I have so far:

<?php
    $alerts = simplexml_load_file('example.xml');
    $guid = $alerts->channel->item->guid;

    if ($guid->count() == 0) {
    print "// No alert";
}
    else {
        echo "<div class='emergency-alert'>".$guid."</div>";
}

?>

Obviously, "guid" is an empty node, but it's returning:

<div class="emergency-alert"> </div>

What am I doing wrong? :(

PS, I've tried hasChildren() and that didn't work either.

@Wrikken is right. XPath is the preferred way of querying XML documents. But answering your question, in your simple case you can check if the node value is empty by casting SimpleXMLElement to string:

if ( !$guid->__toString() ) {
    print "No alert";
}
foreach($alerts->xpath("//item/guid[normalize-space(.)!='']") as $guid){
        echo "<div class='emergency-alert'>".$guid."</div>";
}

What does it do?

  1. xpath: a simple way to query xml documents
  2. normalize-space: the argument string with the leading, trailing, and repeating white spaces stripped (i.e.: <guid> </guid> is not an empty string, it's ' ', but this one turns it to ''
  3. . is the text-content of a node

In PHP a SimpleXMLElement which represents an empty XML element (self-closing tag or empty open/close tag pair with no content) casts to boolean FALSE. This is perhaps a bit unexpected, as normally every object in PHP casts to boolean TRUE:

var_dump((bool) new SimpleXMLElement("<guid/>")); # bool(false)

var_dump((bool) new SimpleXMLElement("<guid></guid>")); # bool(false)

var_dump((bool) new SimpleXMLElement("<guid> </guid>")); # bool(true)

This special rule is documented in the PHP manual on Converting to boolean.

You can make use of that to check whether or not the <guid> element you have is empty. However it's important here, you ask for the element specifically. In your existing code:

$guid = $alerts->channel->item->guid;

you're not asking for a specific <guid> element, but for all which are children of the parent <item> element. These kind of SimpleXMLElement objects cast to boolean true unless they contain zero elements (compare with your use of SimpleXMLElement::count()).

Different to that, if you obtain the first <guid> element by index, you will get a SimpleXMLElement of that index or NULL in case the element does not exist (that means, there is no <guid> element).

Both - non-existing element as NULL or the existing, empty one - will cast to boolean false which can be easily used in your if/else statement:

$guid = $alerts->channel->item->guid[0];
                                    ### zero is the index of the first element
if ((bool) $guid) {
    # non-empty, existing <guid> element
} else {
    # empty or non-existing
}

This then answers your question.