【问题标题】:PHP DOMDocument parentNode->replaceChild causing foreach to skip next itemPHP DOMDocument parentNode->replaceChild 导致 foreach 跳过下一项
【发布时间】:2015-01-23 22:32:21
【问题描述】:

我正在使用 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);

【问题讨论】:

    标签: php iframe foreach html-parser


    【解决方案1】:

    一个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++;
    }
    

    【讨论】:

    • 但是当length等于1的时候,while循环就变成了无限的。那么在这种情况下怎么办
    • 如果 DomNodeList 中的元素没有被替换,那么这将永远循环。
    【解决方案2】:

    今天遇到这个问题,根据答案,我为大家做一个简单的代码解决方案

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

    希望对您有所帮助。

    【讨论】:

    • $i-- 不是必需的,并且正在搞乱 for 循环。
    • @KariKääriäinen $iframes 是参考值,如果您替换 iframe 元素之一,$iframes 的索引会发生变化。但是$i 不是,那么您需要减去$i 以避免超出索引错误并且不跳过某些元素。
    猜你喜欢
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-10
    • 2019-05-14
    • 2021-12-17
    相关资源
    最近更新 更多