Оберните элемент DOM в другой элемент DOM в PHP


Первоначально я задавал вопрос в этом направлении, используя регулярное выражение, но вместо этого мне рекомендовали использовать библиотеку PHP DOM... которая превосходит, но я все еще застрял.

В принципе, я хочу обернуть содержимое <a> в <span>, если оно еще не завернуто в <span>.

<?php
$input = <<<EOT
<html><head></head>
<body bgcolor="#393a36">
    <a href="#"><span style="color:#ffffff;">Link 1</span></a>
    <a href="#">Link 2</a>
    <a href="#"><img src="mypic.gif" />Image Link</a>
    <a href="#"><u>Underlined Link</u></a>
</body>
</html>
EOT;


$doc = new DOMDocument();
$doc->loadHTML($input);
$tags = $doc->getElementsByTagName('a');
foreach ($tags as $tag) {
    $spancount = $tag->getElementsByTagName("span")->length;
    if($spancount == 0){
        $content = nodeContent($tag);
        $element = $doc->createElement('span');
        $element->setAttribute('style','color:#ffffff;');
        $frag = $doc->createDocumentFragment();
        $frag->appendXML($content);
        $element->appendChild($frag);   
        $tag->nodeValue = ""; //clear node
        $tag->appendChild($element);
    }
}
echo $doc->saveHTML();

function nodeContent($n, $outer=false) { 
    $d = new DOMDocument('1.0'); 
    $d->formatOutput = true;
    $b = $d->importNode($n->cloneNode(true),true); 
    $d->appendChild($b);
    $h = $d->saveHTML(); 
    // remove outter tags 
    if (!$outer) $h = substr($h,strpos($h,'>')+1,-(strlen($n->nodeName)+4)); 
    return $h; 
} 

Он обеспечивает такой вывод:

Предупреждение PHP: DOMDocumentFragment::appendxml(): Сущность: строка 1: ошибка синтаксического анализатора: Преждевременное завершение данных в теге img строка 1 в /личные/var/папки/78/78vhgigzhcufexb1kkjsb++++TI/-Tmp-/untitled_3xd..php в строке 24
Предупреждение PHP:Фрагмент DOMDocument::appendxml():Ссылка на изображение в /private/var/папках/78/78vhgigzhcufexb1kkjsb++++TI/-Tmp-/untitled_3xd..php на линии 24 Предупреждение PHP: Фрагмент DOMDocument::appendxml():^в/частных/var/папках/78/78vhgigzhcufexb1kkjsb++++TI/-Tmp-/untitled_3xd..php на линии 24 Предупреждение PHP: DOMNode::appendChild(): Фрагмент документа пуст в /личные/var/папки/78/78vhgigzhcufexb1kkjsb++++TI/-Tmp-/untitled_3xd..php в строке 25

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>  
<head></head>  
<body bgcolor="#393a36">  
    <a href="#"><span style="color:#ffffff;">Link 1</span></a>  
    <a href="#"><span style="color:#ffffff;">Link 2</span></a>  
    <a href="#"><span style="color:#ffffff;"></span></a>  
    <a href="#"><span style="color:#ffffff;"><u>Underlined Link</u></span></a>  
</body>  
</html>

В основном это работает, за исключением того, что он действительно придирчивый, и, как вы можете видеть, он умирает, если здесь есть тег img (или аналогичный) внутри a href.

Каков наилучший способ заставить это работать? Я бьюсь головой об стену уже очень долгое время.

РЕДАКТИРОВАТЬ

Основываясь на отзывах ниже, вот пересмотренный код и выходные данные. Обратите внимание, что текст предшествующий тегу img по какой-то причине не упаковывается. Есть идеи?

$doc = new DOMDocument();
$doc->loadHTML($input);
$tags = $doc->getElementsByTagName('a');
foreach ($tags as $tag) {
    $spancount = $tag->getElementsByTagName("span")->length;
    if($spancount == 0){
    $element = $doc->createElement('span');
    $element->setAttribute('style','color:#ffffff;');
    foreach ($tag->childNodes as $child) {
        $tag->removeChild($child);
        $element->appendChild($child);
    }
    $tag->appendChild($element);

    }
}
echo $doc->saveHTML();

Вывод:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head></head>
<body bgcolor="#393a36">
    <a href="#"><span style="color:#ffffff;">Link 1</span></a>
    <a href="#"><span style="color:#ffffff;">Link 2</span></a>
    <a href="#">Image Link<span style="color:#ffffff;"><img src="mypic.gif"></span></a>
    <a href="#"><span style="color:#ffffff;"><u>Underlined Link</u></span></a>
</body>
</html>
Author: Gustavo Straube, 2010-08-19

2 answers

Зачем беспокоиться о воссоздании узла? Почему бы просто не заменить узел? (Если я понимаю, что вы пытаетесь сделать)...

if($spancount == 0){
    $element = $doc->createElement('span');
    $element->setAttribute('style','color:#ffffff;');
    $tag->parentNode->replaceChild($element, $tag);
    $element->apendChild($tag);
}

Редактировать Упс, похоже, вы пытаетесь охватить все под $tag в промежутке... Попробуйте вместо этого:

if($spancount == 0){
    $element = $doc->createElement('span');
    $element->setAttribute('style','color:#ffffff;');
    foreach ($tag->childNodes as $child) {
        $tag->removeChild($child);
        $element->appendChild($child);
    }
    $tag->appendChild($child);
}

Edit2 Основываясь на ваших результатах, похоже, что foreach не завершается из-за удаления узла... Попробуйте заменить значение foreach следующим образом:

while ($tag->childNodes->length > 0) {
    $child = $tag->childNodes->item(0);
    $tag->removeChild($child);
    $element->appendChild($child);
}
 9
Author: ircmaxell, 2010-08-19 18:12:20

Это отличная информация, и извините, что так поздно пришел на вечеринку, но для меня есть одна ошибка... в конце:

$tag->appendChild($child);

Должно быть

$tag->appendChild($element);

Это единственный способ, которым я мог заставить это работать.

 1
Author: Chris Jones, 2015-03-07 11:59:30