PHP DOMDocument 跳过偶数个元素
PHP DOMDocument skips even elements
您好,我正在使用此方法将所有 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>
Html 用于 iframe
<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不同。任何人都知道如何修复它以替换所有元素?
问题的解释:它可能会跳过所有其他元素,因为例如,一旦删除 iframe,对象(元素列表)就会发生变化其他 iframe 移动以占据被删除的位置。
修复它的一种方法:
// 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
看看它如何跳过所有其他元素?
发生这种情况是因为 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));
您好,我正在使用此方法将所有 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>
Html 用于 iframe
<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不同。任何人都知道如何修复它以替换所有元素?
问题的解释:它可能会跳过所有其他元素,因为例如,一旦删除 iframe,对象(元素列表)就会发生变化其他 iframe 移动以占据被删除的位置。
修复它的一种方法:
// 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
看看它如何跳过所有其他元素?
发生这种情况是因为 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));