A->b->c
可能存在,但 c
可能不存在。我该如何检查它?
将其包装在isset()
中可能会更好。
if(isset($A->b->c)) { // c exists
这样如果$A
或$A->b
不存在,它就不会出错。
c
可能是可选的,但 A
和 b
可能是必需的,因此如果它们未定义,我实际上可能希望获得异常 - 这是检查文档完整性的简单方法。 - davkaisset()
是检查节点是否存在的最佳方法。如果您需要检查节点是否存在并且其内部有内容(即 >
和 <
之间的文本或子节点),则可以使用 empty()
。 如果您仅需要检查节点的存在,则 empty()
将无法完成任务。例如,对于此节点 <b a="zzz"></b>
,empty()
将返回 true
。 - CITBLempty()
没有太大用处。但需要注意的是,如果没有 c
元素,则 isset($A->c) === false
,但 $A->c
返回一个空的 SimpleXMLElement。因此,使用 $c = $A->c;
,则 isset($c) === true
(即使可能会预期 $c !== null
)。 - spikyjtSimpleXML总是返回对象。如果没有子元素,则返回空对象。
if( !empty($a->b)){
var_dump($a->b);
}
empty()
即使节点存在但没有内容也会返回true
。例如,在您的代码示例中,如果$a
包含此内容:<xml><b a="zzz"/></xml>
,则empty($a->b)
将返回true
。因此,这不是一种可靠的检查节点是否存在的方法。但是,如果您需要节点内部的某些内容,即在>
和<
之间,而不关心没有内容的节点,则可以使用empty()
。 - CITBLisset
。if (isset($A->b->c)) { /* c exists */ }
$b = $A->b; // $b is now an empty SimpleXMLElement
$b->getName(); // returns an empty string
isset($b); // returns true
你可能认为使用 isset
来测试子元素是否存在是行不通的,因为如果子元素不存在,我们仍然会得到一个空的 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的情况下,他们设置了这样一个结果:如果b存在,isset($A->b)
返回true,否则返回false,这正好符合我们测试子元素存在性所需的条件。$A->b->c
的存在性。即使中间的b不存在,使用isset($A->b->c)
也完全有效。我认为这里发生的是,PHP首先执行$A->b
,如果b不存在,则得到一个空的SimpleXMLElement,然后在该空SimpleXMLElement上调用__isset('c')
以获取最终结果isset($A->b->c)
。我使用children()
函数并对其进行count()
处理来解决这个问题,如果没有子元素,则在计数调用之前加上@以忽略PHP错误。虽然这很愚蠢,但它确实有效:
$identification = $xml->identification;
if (@count($identification->children()) == 0)
$identification = $xml->Identification;
I hate this..
count($xml->someNode)
。$a->count()
。否则,scippie的解决方案@count($a->children())
也能很好地工作。我发现我不需要@,但旧的PHP实现可能需要它。xpath方法返回匹配的元素数组或false
if(false !== $A->xpath('b/c')) { ...
使用if(isset($A->b){
会出现问题,所以我尝试使用if($A->b){
,它起作用了!
count
和强制转换为布尔值是两种有意义的方法。按照您所描述的方式使用if
是将其转换为布尔值的最短途径。 - Brilliandvar_dump(count($xml->node));
function has_child(?\SimpleXMLElement $parent, string $xpathToChild)
{
return isset($parent) && !empty($parent->xpath('('.$xpathToChild.')[1]'));
}
在检查子节点时,$parent
是一个间接或直接的父节点,而 $xpathToChild
是相对于 $parent
的子节点的 xpath。
()[1]
是因为我们不想选择所有的子节点。一个就足够了。
要检查 $a->b->c 是否存在:
if(has_child($a,'b/c')) { //...
t
。if(has_child($a,'b/c/@t')) { //...