DOM 无法将节点附加到 DOMNodeList (PHP 7.3) 中的元素

Posted

技术标签:

【中文标题】DOM 无法将节点附加到 DOMNodeList (PHP 7.3) 中的元素【英文标题】:DOM cannot append nodes to element from DOMNodeList (PHP 7.3) 【发布时间】:2021-06-13 21:16:54 【问题描述】:

我正在使用 php 7.3 编写一个函数,该函数循环遍历输入中收到的一组节点并将它们添加到文档中。

public function appendChildren($nodes)

    foreach ($nodes as $node)

        $this->appendChild($node);
    

它可以工作,但是当输入值不是数组而是 DOMNodeList 时,它只会循环第一个元素。

重现问题:

<?php

$doc = new DOMDocument();
$doc->formatOutput=true;

$root =  $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'md:root');
$nodes[] = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'KeyInfo');
$nodes[] = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'KeyFile');
$nodes[] = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'KeyStory');
$nodes[] = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'KeyRole');

foreach($nodes as $node)

    $root->appendChild($node);

$nlist = $root->childNodes;
$newroot = $doc->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata', 'md:newroot');


foreach($nlist as $node)

   $newroot->appendChild($node);


echo 'size of root: '.$root->childNodes->count()."\n";
echo 'size of newroot: '.$newroot->childNodes->count()."\n";

$doc->appendChild($newroot);
echo $doc->saveXML();

预期输出:

size of root: 4
size of newroot: 4
<?xml version="1.0"?>
<md:newroot xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
  <md:KeyInfo/>
  <md:KeyFile/>
  <md:KeyStory/>
  <md:KeyRole/>
</md:root>

但是我得到了:

size of root: 3
size of newroot: 1
<?xml version="1.0"?>
<md:newroot xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
  <md:KeyInfo/>
</md:newroot>

循环不完整,不知何故,第一个元素的引用从前一个列表中删除并添加到后者(因此大小为 3)。此外,如果我发表评论

 $newroot->appendChild($node);

循环按预期遍历列表。 appendChild() 函数如何停止循环?为什么会在第一次迭代后发生?

有人能解释一下这种行为吗?

【问题讨论】:

@DanielProtopopov 这确实有效。所以这毕竟是一个迭代的问题!在第二个循环之后长度为 0 的前一个节点结果,我应该在插入之前克隆节点以避免这种副作用吗? (如果您可以将评论作为答案发布,我很乐意将其标记为已接受) 【参考方案1】:

$nlist 在迭代时由于 appendChild 而发生变化。您正在移动内容。可以通过调试看到

for($i = 0; $i < $nlist->length; $i++)

    $newroot->appendChild($nlist->item($i));

所以你需要这样重写

while($nlist->length)

    $newroot->appendChild($nlist->item(0));

【讨论】:

以上是关于DOM 无法将节点附加到 DOMNodeList (PHP 7.3) 中的元素的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 将片段附加到DOM而不是每个节点。

将片段附加到DOM而不是每个节点。

jQuery mobile:当我将选择菜单附加到不同页面上的另一个 DOM 节点时,为啥会中断?

无法附加 <script> 元素

php 必须通过DOMnodeList向后循环才能删除节点

php 必须通过DOMnodeList向后循环才能删除节点