Замените определенный тег <font>на <span>, используя DOM-манипуляции в PHP - PullRequest
2 голосов
/ 19 февраля 2011

Я пытаюсь заменить все теги тегами, используя DOMDocument в PHP, и почти все мои тесты пройдены.Я уверен, что есть другие сценарии, которые я забыл, но сейчас я пропускаю только один:

ОРИГИНАЛ:

<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 был виновником, поскольку он загружал узлы по порядку, поэтому я попыталсяначинать с самого глубокого тега путем обращения массива, но это не сработало, поэтому строка закомментирована.

PS: Если вам интересно, зачем нужен первый цикл, чтобы сохранить все узлы и циклих снова, пожалуйста, прочитайте это: http://robrosenbaum.com/php/domnodelist-gotchas/

Ответы [ 3 ]

2 голосов
/ 19 февраля 2011

Это работает. Я проверял это. : -)

Заменить строку:

$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 голос
/ 19 февраля 2011

Я почти уверен:

$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');
}
1 голос
/ 19 февраля 2011

Когда вы вызываете replaceChild, дочерние узлы элемента font остаются присоединенными к удаленному узлу, а не присоединяются к новому элементу span. Элементы шрифта все индивидуально заменяются, но они больше не привязаны к остальным элементам dom. Вот почему ваш видимый вывод заканчивается на элементе span верхнего уровня, который пуст.

Чтобы решить эту проблему, вам нужно добавить несколько дополнительных строк кода, чтобы скопировать все дочерние узлы из $ font в $ span после replaceNode.

...