A->b->c
可能存在但c
可能不存在。我该如何检查?
17 回答
最好把它包起来isset()
if(isset($A->b->c)) { // c exists
这样,如果存在$A
或$A->b
不存在......它不会爆炸。
SimpleXML 总是返回 Object。如果没有子对象,则返回空对象。
if( !empty($a->b)){
var_dump($a->b);
}
我通过使用该children()
函数并对其进行count()
处理来解决它,如果没有子项,则通过在计数调用之前放置一个 @ 来忽略 PHP 错误。这很愚蠢,但它有效:
$identification = $xml->identification;
if (@count($identification->children()) == 0)
$identification = $xml->Identification;
我讨厌这个..
经过一些实验,我发现检查节点是否存在的唯一可靠方法是使用count($xml->someNode)
.
@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)
.
如果你有 PHP 5.3,你可以使用$a->count()
. 否则,scippie 的解决方案使用@count($a->children())
效果很好。我发现我不需要 @ 但较旧的 PHP 实现可能需要它。
方法 xpath 返回匹配元素的数组或 false
if(false !== $A->xpath('b/c')) { ...
简单地
var_dump(count($xml->node));
使用if(isset($A->b){
给我带来了问题,所以我尝试了
if($A->b){
,它奏效了!
使用 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');
我可以确认在 PHP 5.5.23 中工作的 3 种方法正在使用isset()
count()
或empty()
这是一个显示每个结果的脚本:
我使用辅助函数来检查节点是否是作为函数参数提供的有效节点。
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'];
}
以为我会分享我的经验。在 5.4 上运行,我尝试使用 'isset' 和 'empty' 进行测试,但都不适合我。我最终使用了is_null。
if(!is_null($xml->scheduler->outterList->innerList)) {
//do something
}
命名空间
请注意,如果您在 XML 文件中使用名称空间,则在检查子项时需要在函数调用中包含这些名称空间,否则每次都会返回零:
if ($XMLelement->children($nameSpace,TRUE)->count()){
//do something here
}
我不能说早期版本,但在 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是否存在并且在所需的位置。
你可以试试:
if($A->b->c && $A->b->c != '')
if($A->b->c != null) //c exists
如果c
不存在,它的值将是null
(或者,更准确地说,它没有值)。但是请注意,要使其正常工作,两者A
都不b
需要是null
. 否则,PHP 会抛出错误(我认为)。