使用PHP中的DOM操作将<span>标记替换为<span> </span> </font>

时间:2011-02-19 01:44:31

标签: php dom domdocument

我正在尝试使用PHP中的DOMDocument用标签替换所有标签,几乎所有测试都通过了。我确定还有其他我忘记的情景,但就目前而言,我只缺少一个:

ORIGINAL:

<p><font color="#ff0000">BEFORE <font color="#00ff00">BEFORE <font color="#0000ff">VAL</font> AFTER</font> AFTER</font></p>

结果:

<p><span style="color: #ff0000">BEFORE BEFORE VAL AFTER AFTER</span></p>

此代码的PHP代码:

$html = '<p><font color="#ff0000">BEFORE <font color="#00ff00">BEFORE <font color="#0000ff">VAL</font> AFTER</font> AFTER</font></p>';

$dom = new DOMDocument();
$dom->loadHTML($html);

foreach($dom->getElementsByTagName('font') as $node) {
    $font_nodes[] = $node;
}

//$font_nodes = array_reverse($font_nodes);

foreach($font_nodes as $font) {
    $a_style = array_filter(explode(';', $font->getAttribute('style')));

    if($a_color = $font->getAttribute('color')) {
        $a_style[] = 'color: '.$a_color;
    }

    $span = $dom->createElement('span', $font->nodeValue);
    $span->setAttribute('style', implode('; ', $a_style));

    $font->parentNode->replaceChild($span, $font);
}

echo preg_replace("#(<!DOCTYPE.+|<\/?html>|<\/?body>)#", '', $dom->saveHTML());

我认为getElementsByTagName是罪魁祸首,因为它按顺序加载节点,所以我试图通过反转数组从最深的标签开始,但是这不起作用所以线被评论。 / p>

P.S:如果您想知道为什么需要第一个循环来保存所有节点并再次循环它们,请阅读:http://robrosenbaum.com/php/domnodelist-gotchas/

3 个答案:

答案 0 :(得分:2)

这有效。我测试了它。 : - )

替换行:

$span = $dom->createElement('span', $font->nodeValue);

有了这个:

$span = $dom->createElement('span');
$children = array(); 
foreach ($font->childNodes as $child) $children[] = $child;
foreach ($children as $child) $span->appendChild($child);

答案 1 :(得分:1)

当您调用replaceChild时,font元素的子节点仍然附加到已删除的节点,而不是附加到新的span元素。字体元素都被单独替换,但它们不再附加到其余的dom元素。这就是为什么你的可见输出结束于顶级span元素,它是空的。

要解决此问题,您需要添加一些额外的代码行,以便在replaceNode之后将所有子节点从$ font复制到$ span。

答案 2 :(得分:1)

我很确定:

$font->parentNode->replaceChild($span, $font);

是你的罪魁祸首,因为嵌套元素的父元素不再存在于文档中。您在正确的轨道上尝试颠倒顺序,但是当您反转时,您覆盖了更改,因为您使用的是仍包含子字体的父字体的副本。 我没有可以在上测试的系统,但我想像这样的代码会按照您的要求执行:

$dom = new DOMDocument();
$dom->loadHTML($html);

$font_nodes = $dom->getElementsByTagName('font');
while($font = $font_nodes->item(0)) {
    $a_style = array_filter(explode(';', $font->getAttribute('style')));

    if($a_color = $font->getAttribute('color')) {
        $a_style[] = 'color: '.$a_color;
    }

    $span = $dom->createElement('span', $font->nodeValue);
    $span->setAttribute('style', implode('; ', $a_style));

    $font->parentNode->replaceChild($span, $font);

    $font_nodes = $dom->getElementsByTagName('font');
}