PHP DOMDocument parentNode->replaceChild导致foreach跳过下一项

mv1qrgav  于 2023-10-15  发布在  PHP
关注(0)|答案(3)|浏览(102)

我正在使用DOMDocument解析$content变量中的html,以将所有iframe替换为图像。foreach只是替换了ODD iframe。我已经删除了foreach中的所有代码,发现导致这一点的代码是:'$iframe->parentNode->replaceChild($link,$iframe);'
为什么foreach会跳过所有奇怪的iframe呢?
代码:

$count = 1;
        $dom = new DOMDocument;
        $dom->loadHTML($content);
        $iframes = $dom->getElementsByTagName('iframe');
        foreach ($iframes as $iframe) {

            $src = $iframe->getAttribute('src');
            $width = $iframe->getAttribute('width');
            $height = $iframe->getAttribute('height');

            $link = $dom->createElement('img');
            $link->setAttribute('class', 'iframe-'.self::return_video_type($iframe->getAttribute('src')).' iframe-'.$count.' iframe-ondemand-placeholderImg');
            $link->setAttribute('src', $placeholder_image);
            $link->setAttribute('height', $height);
            $link->setAttribute('width', $width);
            $link->setAttribute('data-iframe-src', $src);

            $iframe->parentNode->replaceChild($link, $iframe);

            echo "here:".$count;
            $count++;
        }

        $content = $dom->saveHTML();

        return $content;

这是有问题的代码行

$iframe->parentNode->replaceChild($link, $iframe);
mbzjlibv

mbzjlibv1#

一个DOMNodeList,比如从getElementsByTagName返回的,是“live”:
也就是说,对底层文档结构的更改会反映在所有相关的NodeList中。对象
因此,当您删除该元素时(在本例中,通过用另一个元素替换它),它不再存在于节点列表中,并且行中的下一个元素将占据其在索引中的位置。然后,当foreach命中下一个迭代,因此下一个索引,一个将被有效地跳过。
不要像这样通过foreach从DOM中删除元素。
一种可行的方法是使用while循环来替换和替换,直到$iframes节点列表为空。

示例:

while ($iframes->length) {
    $iframe = $iframes->item(0);

    $src = $iframe->getAttribute('src');
    $width = $iframe->getAttribute('width');
    $height = $iframe->getAttribute('height');

    $link = $dom->createElement('img');
    $link->setAttribute('class', 'iframe-'.self::return_video_type($iframe->getAttribute('src')).' iframe-'.$count.' iframe-ondemand-placeholderImg');
    $link->setAttribute('src', $placeholder_image);
    $link->setAttribute('height', $height);
    $link->setAttribute('width', $width);
    $link->setAttribute('data-iframe-src', $src);

    $iframe->parentNode->replaceChild($link, $iframe);

    echo "here:".$count;
    $count++;
}
whitzsjs

whitzsjs2#

今天面对这个问题,在答案的引导下,我为大家做了一个简单的代码解决方案

$iframes = $dom->getElementsByTagName('iframe');
for ($i=0; $i< $iframes->length; $i++) {
    $iframe = $iframes->item($i);
    if("condition to replace"){
        // do some replace thing
        $i--;
    }
}

希望这对你有帮助。

hs1ihplo

hs1ihplo3#

如果正在寻找一种方法来跳过一些元素,并替换其他元素。当你改变数组时,它确实跳过了迭代。在这个例子中,你可以看到如果代码没有以foo/bar开头的属性src,代码将继续进行下一次迭代。

$elems = $doc->getElementsByTagName('img');
$amountElems = $elems->length;
for ($i=($amountElems-1); $i >= 0; $i--) {       
    $elem = $elems->item($i);
    if (!str_starts_with($elem->getAttribute('src'), '/foo/bar/')) continue;
    // TLDR some code to alter or create a new elem 
    $elem->parentNode->removeChild($elem);
}

相关问题