64

A->b->c可能存在但c可能不存在。我该如何检查?

4

17 回答 17

130

最好把它包起来isset()

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

这样,如果存在$A$A->b不存在......它不会爆炸。

于 2009-10-13T18:41:21.400 回答
40

SimpleXML 总是返回 Object。如果没有子对象,则返回空对象。

if( !empty($a->b)){
  var_dump($a->b);
}
于 2011-03-17T20:03:04.357 回答
8

我通过使用该children()函数并对其进行count()处理来解决它,如果没有子项,则通过在计数调用之前放置一个 @ 来忽略 PHP 错误。这很愚蠢,但它有效:

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

我讨厌这个..

于 2010-11-24T15:11:52.567 回答
7

经过一些实验,我发现检查节点是否存在的唯一可靠方法是使用count($xml->someNode).

这是一个测试用例:https ://gist.github.com/Thinkscape/6262156

于 2014-04-10T12:52:08.123 回答
5

@null 的答案是正确的 - 最简单的方法是使用isset

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

但是,其原因并不明显(至少对我而言),并且此页面上有相当多的错误信息。我花了一段时间才正确理解它,所以我想分享我学到的东西。

正如一些人所指出的,当您访问一个不存在的 SimpleXMLElement 子元素时,您得到的实际上是一个“空”的 SimpleXMLElement,而不是 false 或 null。

例如,如果 b 不存在:

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

所以你可能会认为isset用来检测children是否存在是行不通的,因为如果children不存在,我们仍然会得到一个空的SimpleXMLObject,所以isset必然会返回true。

但事实上它没有:

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

这让我很惊讶!原因是它isset不是常规函数,而是 PHP 语言构造。当您调用isset($A->b)PHP 时,不会先计算$A->b然后将结果作为参数传递给isset(). 相反,在不可访问的对象属性上调用 isset 时的行为是调用__isset()类的重载方法(如此处所述:https://www.php.net/manual/en/language.oop5.overloading.php#object。伊塞特

所以类的作者可以isset($A->b)独立于 的结果来控制 的结果$b = $A->b。在 SimpleXMLElement 的情况下,他们将其设置为isset($A->b)如果 b 存在则返回 true,否则返回 false——这正是我们测试子元素是否存在所需要的。

对此的另一个脚注 - 最初的问题是关于测试$A->b->c. isset($A->b->c)即使中间 b 不存在,using也可以完美地解决这个问题。我认为这里发生的事情是 PHP 首先执行$A->b,如果 b 不存在,它会得到一个空的 SimpleXMLElement,然后它会调用__isset('c')那个空的 SimpleXMLElement 来获得isset($A->b->c).

于 2020-08-05T08:14:21.697 回答
4

如果你有 PHP 5.3,你可以使用$a->count(). 否则,scippie 的解决方案使用@count($a->children())效果很好。我发现我不需要 @ 但较旧的 PHP 实现可能需要它。

于 2011-03-23T23:05:59.680 回答
3

方法 xpath 返回匹配元素的数组或 false

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

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

于 2013-09-25T10:32:06.447 回答
3

简单地

var_dump(count($xml->node));
于 2017-03-15T18:04:28.700 回答
2

使用if(isset($A->b){ 给我带来了问题,所以我尝试了 if($A->b){ ,它奏效了!

于 2012-06-06T12:49:51.147 回答
2

使用 xpath:

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

其中$parent是要检查的子节点的间接或直接父节点,并且$xpathToChild是子节点相对于 的 xpath $parent

()[1]是因为我们不想选择所有的子节点。一个就够了。

检查 $a->b->c 是否存在:

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

您还可以检查属性。检查节点c是否具有该t属性。

has_child($a,'b/c/@t');
于 2017-04-18T13:09:17.460 回答
1

我可以确认在 PHP 5.5.23 中工作的 3 种方法正在使用isset() count()empty()

这是一个显示每个结果的脚本:

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

于 2015-04-15T18:43:09.837 回答
1

我使用辅助函数来检查节点是否是作为函数参数提供的有效节点。

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

使用示例:

public function getIdFromNode($node) {
  if (!self::isValidNode($node)) {
    return 0;
  }
  return (int)$node['id'];
}
于 2018-06-07T13:27:23.413 回答
0

以为我会分享我的经验。在 5.4 上运行,我尝试使用 'isset' 和 'empty' 进行测试,但都不适合我。我最终使用了is_null

if(!is_null($xml->scheduler->outterList->innerList)) {
    //do something
}
于 2013-08-02T21:29:59.377 回答
0

命名空间

请注意,如果您在 XML 文件中使用名称空间,则在检查子项时需要在函数调用中包含这些名称空间,否则每次都会返回零:

if ($XMLelement->children($nameSpace,TRUE)->count()){
    //do something here 
}
于 2014-10-01T17:26:55.267 回答
0

我不能说早期版本,但在 PHP 8.0 中,使用以下单行函数:

function elementExists(?SimpleXMLElement $element) : bool {
  return is_null($element)?false:@count($element);
}

$A = new SimpleXMLElement('<A><b><c/></b></A>');  // doc contains c
$B = new SimpleXMLElement('<B><b/></B>');         // doc does not contain c 
$C = new SimpleXMLElement('<C><x><c/></x></C>');  // doc contains c but different heirarchy

print '$A contains ->b->c : ' . (elementExists($A->b->c)?"true":"false") . PHP_EOL;
print '$B contains ->b->c : ' . (elementExists($B->b->c)?"true":"false") . PHP_EOL;
print '$C contains ->b->c : ' . (elementExists($C->b->c)?"true":"false") . PHP_EOL;

返回

$A contains ->b->c : true
$B contains ->b->c : false
$C contains ->b->c : false

IE。正确确定c是否存在并且在所需的位置。

于 2021-07-13T13:21:58.020 回答
-2

你可以试试:

if($A->b->c && $A->b->c != '')
于 2011-06-21T16:08:37.903 回答
-26
if($A->b->c != null) //c exists

如果c不存在,它的值将是null(或者,更准确地说,它没有值)。但是请注意,要使其正常工作,两者A都不b需要是null. 否则,PHP 会抛出错误(我认为)。

于 2009-10-13T15:17:17.823 回答