PHP DOMDocument跳过偶数元素

时间:2016-07-14 10:50:29

标签: php domdocument

您好我使用此方法将所有iframe和img标记替换为span标记

    $string = clean($string);
    $dom = new \DOMDocument;
    $dom->loadHTML(mb_convert_encoding($string, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $iframes = $dom->getElementsByTagName('iframe');

    foreach($iframes as $iframe) {
        $src = $iframe->getAttribute('src');
        $span = $dom->createElement('span');
        $span->setAttribute('title', $src);
        $span->setAttribute('class', 'lazy-youtube');
        $iframe->parentNode->replaceChild($span, $iframe);
    }

    $images = $dom->getElementsByTagName('img');

    foreach($images as $image) {
        $src = $image->getAttribute('src');
        $span = $dom->createElement('span');
        $span->setAttribute('title', $src);
        $span->setAttribute('class', 'lazy-image');
        $image->parentNode->replaceChild($span, $image);
    }

    $html = $dom->saveHTML();

    return clean($html);

但问题是它会跳过元素,它总是像这样

// Iframe
<span>
<iframe>
<span>
<iframe>
<span>
<iframe>
<span>
<iframe>

// Img
<span>
<img>
<span>
<img>
<span>
<img>
<span>
<img>

iframe的Html

<div class="content">
<p>
   <iframe frameborder="0" height="315" src="https://www.youtube.com/embed/T6kG5vuPVSs?rel=0" width="560"></iframe>
<p>
</p>
   <iframe frameborder="0" height="315" src="https://www.youtube.com/embed/GjnadPBMJGs?rel=0" width="560"></iframe>
<p>
</p>
   <iframe frameborder="0" height="315" src="https://www.youtube.com/embed/KYm8SLLQ0kk?rel=0" width="560"></iframe>
<p>
</p>
   <iframe frameborder="0" height="315" src="https://www.youtube.com/embed/xUVz4nRmxn4?rel=0" width="560"></iframe>
<p>
</p>
   <iframe frameborder="0" height="315" src="https://www.youtube.com/embed/hmZ6ziQJByY?rel=0" width="560"></iframe>
</p>
</div>

所有相同类型的元素都具有相同的属性,只有src是不同的。任何人都知道如何修复它来替换所有元素?

2 个答案:

答案 0 :(得分:1)

解释问题:它可能正在跳过所有其他元素,因为一旦删除iframe,对象(元素列表)会以所有其他iframe转换为ocuppy的方式发生变化删除的地方。

修复的一种方法:

// code
$iframes = $dom->getElementsByTagName('iframe');
while($iframes->length > 0){ // while there are still frames left to change
    foreach($iframes as $iframe) {
        // your regular code to replace iframe with span
        // break; // this makes it easier to understand, but not really necessary
    }
    $iframes = $dom->getElementsByTagName('iframe'); // get the (remaining) skipped frames until there is none left
}
// code

不要忘记对图像执行相同的操作。

以下是了解问题的更好方法:

 1 - List of iframes
 iframe1  iframe2  iframe3  iframe4 iframe5 [...]
    /\ - current item in loop

 2 - Replacing iframe1, it comes out of the list (since I just want iframes), so the list is now:
 iframe2  iframe3  iframe4  iframe5 [...]
    /\

 3 - Loop continues and it goes to the next item
 iframe2  iframe3  iframe4  iframe5 [...]
             /\ - current item in loop

看看它会如何跳过其他所有元素?

答案 1 :(得分:0)

这是因为foreach不会复制迭代对象,并且在替换子项时会修改DOMNodeList元素。 迭代DOMNodeList的正确方法是:

$elements = $domElement->getElementsByTagName("iframe");
while($elements->length > 0) {
    $oldNode = $elements->item(0);
    $newNode = $dom->createElement("image");
    $oldNode->parentNode->replaceChild($oldNode, $newNode);
}

使用相同的逻辑,如果您需要将子元素从旧节点移动到新节点,您可以这样做:

while($oldNode->childNodes->length > 0)
    $newNode->appendChild($oldNode->childNodes->item(0));