php SimpleXML check if a child exists

后端 未结 16 1946
粉色の甜心
粉色の甜心 2020-11-27 06:24

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

相关标签:
16条回答
  • 2020-11-27 06:48
    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).

    0 讨论(0)
  • 2020-11-27 06:48

    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'];
    }
    
    0 讨论(0)
  • 2020-11-27 06:48

    You could try:

    if($A->b->c && $A->b->c != '')
    
    0 讨论(0)
  • 2020-11-27 06:51

    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');
    
    0 讨论(0)
  • 2020-11-27 06:53

    Method xpath returns array of matched elements or false

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

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

    0 讨论(0)
  • 2020-11-27 06:53

    The answer by @null is correct - the simplest way to do this is with isset

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

    However, the reasons for it are not obvious (to me at least), and there's a fair bit of misinformation on this page. It took me a while to understand it properly so I wanted to share what I learned.

    As some people have pointed out, when you access a non-existent child of a SimpleXMLElement, what you get is actually an 'empty' SimpleXMLElement, as opposed to false or null.

    So for example if b doesn't exist:

    $b = $A->b; // $b is now an empty SimpleXMLElement
    $b->getName(); // returns an empty string
    isset($b); // returns true
    

    So you might think that using isset to test for the existence of children is not going to work, because if the child doesn't exist, we still get an empty SimpleXMLObject, so isset is bound to return true.

    But in fact it doesn't:

    isset($A->b); // returns false
    

    This was pretty surprising to me! The reason is that isset is not a regular function but a PHP language construct. When you call isset($A->b) PHP does not first calculate $A->b and then pass the result as an argument to isset(). Instead the behaviour when isset is called on an inaccessible object property is to call the __isset() overloading method on the class (as explained here: https://www.php.net/manual/en/language.oop5.overloading.php#object.isset)

    So the author of the class can control the result of isset($A->b) independently from the result of $b = $A->b. In the case of SimpleXMLElement, they set it up so that isset($A->b) returns true if b exists and false otherwise - exactly what we need for testing the existence of a child element.

    One further footnote to this - the original question asked about testing the existence of $A->b->c. Using isset($A->b->c) works perfectly for this as well, even if the intermediate b doesn't exist. I think what's happening here is that PHP first does $A->b, and if b doesn't exist, it gets an empty SimpleXMLElement, then it calls __isset('c') on that empty SimpleXMLElement to get the final result of isset($A->b->c).

    0 讨论(0)
提交回复
热议问题