【发布时间】:2010-12-06 08:37:06
【问题描述】:
A->b->c 可能存在,但c 可能不存在。如何查看?
【问题讨论】:
-
请选择一个新答案
A->b->c 可能存在,但c 可能不存在。如何查看?
【问题讨论】:
最好将其包装在isset()中
if(isset($A->b->c)) { // c exists
这样,如果 $A 或 $A->b 不存在......它不会爆炸。
【讨论】:
c 可能是可选的,但 A 和 b 可能是必需的,因此如果未定义它们,我实际上可能希望获得一个例外 - 检查文档完整性的简单方法
isset() 是检查节点是否存在的最佳途径。如果您需要检查节点是否存在并且里面有东西,您可以使用empty(),即在> 和<(文本或子节点)之间。如果您只需要检查节点是否存在,那么empty() 将不会这样做。例如,empty() 将为此节点返回 true <b a="zzz"></b>
empty() 没有多大用处。然而,重要的是要注意,如果没有 c 元素,isset($A->c) === false,但 $A->c 返回一个空的 SimpleXMLElement。所以使用$c = $A->c;,然后是isset($c) === true(即$c !== null,尽管这可能是预期的)。
SimpleXML 总是返回对象。如果没有子对象,则返回空对象。
if( !empty($a->b)){
var_dump($a->b);
}
【讨论】:
empty()即使节点存在但没有内容也会返回true。例如,在您的代码示例中,如果$a 包含以下内容:<xml><b a="zzz"/></xml>,那么empty($a->b) 将返回true。因此,这不是检查节点是否存在的可靠方法。你可以使用empty(),但如果你需要一个节点内的东西,即在>和<之间,并且对没有内容的节点不感兴趣
我通过使用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)
所以类的作者可以独立于$b = $A->b的结果控制isset($A->b)的结果。在 SimpleXMLElement 的情况下,他们将其设置为 isset($A->b) 如果 b 存在则返回 true,否则返回 false - 这正是我们测试子元素是否存在所需要的。
对此还有一个脚注——最初的问题是关于测试$A->b->c 的存在性。即使中间 b 不存在,使用 isset($A->b->c) 也可以完美地解决这个问题。我认为这里发生的事情是PHP首先执行$A->b,如果b不存在,它会得到一个空的SimpleXMLElement,然后在那个空的SimpleXMLElement上调用__isset('c')以获得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){
并且成功了!
【讨论】:
count 和强制转换为布尔值是有意义的两种方式。正如您所描述的那样使用if 是转换为布尔值的最短方法。
使用 xpath:
function has_child(\SimpleXMLElement $parent=null, string $xpathToChild)
{
return isset($parent) && !empty($parent->xpath('('.$xpathToChild.')[1]'));
}
其中$parent 是要检查的子节点的间接或直接父节点,$xpathToChild 是子节点相对于$parent 的 xpath。
()[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
即。正确判断 c 是否存在并在所需位置。
【讨论】:
你可以试试:
if($A->b->c && $A->b->c != '')
【讨论】:
if($A->b->c != null) //c exists
如果c 不存在,则其值为null(或者更准确地说,它没有值)。但是请注意,要使其正常工作,A 和 b 都不需要是 null。否则,PHP 会抛出错误(我认为)。
【讨论】: