在PHP中的另一个DOM元素中包装DOM元素

时间:2010-08-19 17:24:17

标签: php html dom

我最初使用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():实体:第1行:解析器错误:/ private / var / folders / 78 / 78vHGigZHcuFeXB1KKJSb ++++ TI / -Tmp-中标记img第1行中数据的过早结束第24行的/untitled_3xd..php
  PHP警告:DOMDocumentFragment :: appendXML():第24行的/private/var/folders/78/78vHGigZHcuFeXB1KKJSb++++TI--Tmp-/untitled_3xd..php中的图像链接   PHP警告:DOMDocumentFragment :: appendXML():^ in /private/var/folders/78/78vHGigZHcuFeXB1KKJSb++++TI/-Tmp-/untitled_3xd..php 24行   PHP警告:DOMNode :: appendChild():文档片段在第25行的/private/var/folders/78/78vHGigZHcuFeXB1KKJSb++++ TTI-/untitled_3xd..php中为空

<!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>

2 个答案:

答案 0 :(得分:9)

为什么要重新创建节点呢?为什么不直接替换节点? (如果我理解你要做的事情)......

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);
}

答案 1 :(得分:1)

这是一个很好的信息,很抱歉这么晚才进入聚会,但最后还有一个错误......最后:

$tag->appendChild($child);

应该是

$tag->appendChild($element);

这是我能让它发挥作用的唯一方法。