Wrap DOM-элемент в другом элементе DOM в PHP

Я изначально задал вопрос по этим строкам с помощью Regex, но мне было рекомендовано вместо этого использовать библиотеку 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 (): Entity: строка 1: ошибка парсера: преждевременный конец данных в теге img line 1 in / private / var / folders / 78 / 78vHGigZHcuFeXB1KKJSb ++++ TI / -Tmp- / untitled_3xd. .php в строке 24
PHP Предупреждение: DOMDocumentFragment :: appendXML (): ссылка на изображение в /private/var/folders/78/78vHGigZHcuFeXB1KKJSb++++TI/-Tmp-/untitled_3xd..php в строке 24 PHP Предупреждение: DOMDocumentFragment :: appendXML (): ^ in /private/var/folders/78/78vHGigZHcuFeXB1KKJSb++++TI/-Tmp-/untitled_3xd..php on line 24 PHP Предупреждение: DOMNode :: appendChild (): Фрагмент документа пуст в / private / var / folders /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> 

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

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

Edit Whoops, похоже, вы пытаетесь обернуть все под $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); } 

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

 $tag->appendChild($child); 

должно быть

 $tag->appendChild($element); 

Это единственный способ заставить это работать.