php SimpleXML 检查孩子是不是存在
Posted
技术标签:
【中文标题】php SimpleXML 检查孩子是不是存在【英文标题】:php SimpleXML check if a child existsphp SimpleXML 检查孩子是否存在 【发布时间】:2010-12-06 08:37:06 【问题描述】:A->b->c
可能存在,但c
可能不存在。如何查看?
【问题讨论】:
请选择一个新答案 【参考方案1】:最好将其包装在isset()
中
if(isset($A->b->c)) // c exists
这样,如果 $A
或 $A->b
不存在......它不会爆炸。
【讨论】:
这似乎比其他答案更整洁,但实际上 SimpleXMLElement 返回并为任何不存在的请求节点清空 SimpleXMLElement 对象。所以 empty() 方法似乎是最好的方法。 另外,c
可能是可选的,但 A
和 b
可能是必需的,因此如果未定义它们,我实际上可能希望获得一个例外 - 检查文档完整性的简单方法
@spikyjt isset()
是检查节点是否存在的最佳途径。如果您需要检查节点是否存在并且里面有东西,您可以使用empty()
,即在>
和<
(文本或子节点)之间。如果您只需要检查节点是否存在,那么empty()
将不会这样做。例如,empty()
将为此节点返回 true
<b a="zzz"></b>
@CITBL 你是对的,empty()
没有多大用处。然而,重要的是要注意,如果没有 c
元素,isset($A->c) === false
,但 $A->c
返回一个空的 SimpleXMLElement。所以使用$c = $A->c;
,然后是isset($c) === true
(即$c !== null
,尽管这可能是预期的)。【参考方案2】:
SimpleXML 总是返回对象。如果没有子对象,则返回空对象。
if( !empty($a->b))
var_dump($a->b);
【讨论】:
显然这是一个特性而不是一个错误。注意到这一点非常重要。如果对象不存在,则访问对象的子对象将创建它。 这应该是公认的答案,会为我节省一些时间和挫败感:-) 错误答案。因为empty()
即使节点存在但没有内容也会返回true
。例如,在您的代码示例中,如果$a
包含以下内容:<xml><b a="zzz"/></xml>
,那么empty($a->b)
将返回true
。因此,这不是检查节点是否存在的可靠方法。你可以使用empty()
,但如果你需要一个节点内的东西,即在>
和<
之间,并且对没有内容的节点不感兴趣【参考方案3】:
我通过使用children()
函数并在其上执行count()
来解决它,如果没有子级,则通过在计数调用之前放置一个@ 来忽略php 错误。这很愚蠢,但它有效:
$identification = $xml->identification;
if (@count($identification->children()) == 0)
$identification = $xml->Identification;
我讨厌这个..
【讨论】:
你是完全正确的(这就是为什么我说'我讨厌这个......'),但是当你知道发生任何错误时,你希望它被忽略,那么这很好。跨度> 【参考方案4】:经过一些实验,我发现检查节点是否存在的唯一可靠方法是使用count($xml->someNode)
。
这是一个测试用例:https://gist.github.com/Thinkscape/6262156
【讨论】:
【参考方案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)
所以类的作者可以独立于$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)
的最终结果。
【讨论】:
【参考方案6】:如果你有 PHP 5.3,你可以使用$a->count()
。否则,scippie 使用@count($a->children())
的解决方案效果很好。我发现我不需要 @ 但较旧的 PHP 实现可能需要它。
【讨论】:
这应该是接受的答案,目前接受的是错误的。【参考方案7】:方法 xpath 返回匹配元素的数组或 false
if(false !== $A->xpath('b/c')) ...
http://www.php.net/manual/ru/simplexmlelement.xpath.php
【讨论】:
不,文档表明如果出现错误,它会返回 FALSE,而不是如果路径没有返回结果。 测试过这个,@Brian 是正确的,只有出错时才会返回false。不要使用这个检查,它总是会返回一个(空)节点。【参考方案8】:简单
var_dump(count($xml->node));
【讨论】:
在 PHP7.2 中,他们在计算未实现 Countable 接口的内容时添加了警告。因此,应该考虑到这一点,并更好地使用 isset() 而不是 count()【参考方案9】:使用if(isset($A->b)
给了我问题,所以我尝试了
if($A->b)
并且成功了!
【讨论】:
count
和强制转换为布尔值是有意义的两种方式。正如您所描述的那样使用if
是转换为布尔值的最短方法。【参考方案10】:
使用 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');
【讨论】:
【参考方案11】:我可以在 PHP 5.5.23 中确认工作的 3 种方法是使用 isset()
count()
或 empty()
这是一个显示每个结果的脚本:
https://gist.github.com/mchelen/306f4f31f21c02cb0c24
【讨论】:
【参考方案12】:我使用辅助函数来检查节点是否是函数中作为参数提供的有效节点。
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'];
【讨论】:
【参考方案13】:我想分享一下我的经验。在 5.4 上运行,我尝试使用 'isset' 和 'empty' 进行测试,但都不适合我。我最终使用了 is_null。
if(!is_null($xml->scheduler->outterList->innerList))
//do something
【讨论】:
【参考方案14】:命名空间
请注意,如果您在 XML 文件中使用名称空间,则在检查子项时需要在函数调用中包含这些名称空间,否则每次都会返回零:
if ($XMLelement->children($nameSpace,TRUE)->count())
//do something here
【讨论】:
【参考方案15】:我不能说早期版本,但在 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 是否存在并在所需位置。
【讨论】:
【参考方案16】:你可以试试:
if($A->b->c && $A->b->c != '')
【讨论】:
【参考方案17】:if($A->b->c != null) //c exists
如果c
不存在,则其值为null
(或者更准确地说,它没有值)。但是请注意,要使其正常工作,A
和 b
都不需要是 null
。否则,PHP 会抛出错误(我认为)。
【讨论】:
这不是个好主意。如果节点不存在,c 将是一个空对象,这与 NULL 不同。 补充@spikyjt所说的,如果节点c在$A->b中不存在,则返回一个空的SimpleXMLElement。 SimpleXMLElement 的有效实例不为空;该表达式的计算结果始终为 true。以上是关于php SimpleXML 检查孩子是不是存在的主要内容,如果未能解决你的问题,请参考以下文章