PHP DOM - 剥离span标记,留下其内容

时间:2011-01-11 22:20:20

标签: php parsing dom

我希望将标记视为:

<span class="test">Some text that is <strong>bolded</strong> and contains a <a href="#">link</a>.</span>

并找到PHP中用于剥离跨度的最佳方法,以便剩下的就是:

Some text that is <strong>bolded</strong> and contains a <a href="#">link</a>.

我已经阅读了许多关于使用PHP DOM而不是正则表达式解析HTML的其他问题,但是我们无法找到一种方法来剥离PHP DOM的跨度,使HTML内容保持不变。最终目标是能够剥离所有span标签的文档,留下其内容。这可以用PHP DOM完成吗?是否有一种方法可以提供更好的性能,而不依赖于字符串解析而不是DOM解析?

到目前为止,我使用了正则表达式,没有任何问题:

/<(\/)?(span)[^>]*>/i

但我的兴趣在于成为更好的PHP程序员。而且由于总是可以使用格式错误的标记来破坏正则表达式,我正在寻找更好的方法。我还考虑使用strip_tags(),执行以下操作:

public function strip_tags( $content, $tags_to_strip = array() )
{
    // All Valid XHTML tags
 $valid_tags = array(
  'a','abbr','acronym','address','area','b','base','bdo','big','blockquote','body','br','button','caption','cite',
  'code','col','colgroup','dd','del','dfn','div','dl','DOCTYPE','dt','em','fieldset','form','h1','h2','h3','h4',
  'h5','h6','head','html','hr','i','img','input','ins','kbd','label','legend','li','link','map','meta','noscript',
  'object','ol','optgroup','option','p','param','pre','q','samp','script','select','small','span','strong','style',
  'sub','sup','table','tbody','td','textarea','tfoot','th','thead','title','tr','tt','ul','var'
 );

    // Remove each tag to strip from the valid_tags array
 foreach ( $tags_to_strip as $tag ){
  $ndx = array_search( $tag, $valid_tags );
  if ( $ndx !== false ){
   unset( $valid_tags[ $ndx ] );
  }
 }

    // convert valid_tags array into param for strip_tags
 $valid_tags = implode( '><', $valid_tags );
 $valid_tags = "<$valid_tags>";

 $content = strip_tags( $content, $valid_tags );
 return $content;
}

但这仍然在解析字符串,而不是DOM解析。因此,如果文本格式不正确,则可能剥离太多。很多人都建议使用Simple HTML DOM Parser,但是看一下源代码,它似乎也在使用正则表达来解析html。

这可以通过PHP5的DOM完成,还是有更好的方法来剥离标签,保持内容不变。使用Tidy或HTML Purifier清理文本然后在其上使用正则表达式/ HTML简单HTML DOM解析器是不好的做法?

phpQuery这样的图书馆似乎过于沉重,似乎应该是一项简单的任务。

2 个答案:

答案 0 :(得分:1)

我使用以下函数删除节点而不删除其子节点:

function DOMRemove(DOMNode $from) {
    $sibling = $from->firstChild;
    do {
        $next = $sibling->nextSibling;
        $from->parentNode->insertBefore($sibling, $from);
    } while ($sibling = $next);
    $from->parentNode->removeChild($from);    
}

每个例子:

$dom = new DOMDocument;
$dom->load('myhtml.html');

$nodes = $dom->getElementsByTagName('span');
foreach ($nodes as $node) {
    DOMRemove($node);
}
echo $dom->saveHTML();

会给你:

Some text that is <strong>bolded</strong> and contains a <a href="#">link</a>.

虽然这个:

$nodes = $dom->getElementsByTagName('a');
foreach ($nodes as $node) {
    DOMRemove($node);
}
echo $dom->saveHTML();

会给你:

<span class="test">Some text that is <strong>bolded</strong> and contains a link.</span>

答案 1 :(得分:0)

那么,

根据我的经验,每次使用DOM时,与简单的stri操作相比,我的性能都有所下降。

使用您的函数,您尝试严格过滤有效的XHTML标记,但是您不需要手动比较的循环,因为您可以通过本机函数将所有这些任务分配给PHP解释器。

当然,你已经很好地实现了非常好的性能(对我来说,0.0002毫秒),但是你可以尝试将功能组合在一起,让每个功能都能完成你自己的工作。

看看你会理解我在说什么:

$text = '<span class="test">Some text that is <strong>bolded</strong> and contains a <a href="#">link</a>.</span>';

$validTags = array( 'a','abbr','acronym','address','area','b','base','bdo','big','blockquote','body','br','button','caption','cite',
  'code','col','colgroup','dd','del','dfn','div','dl','DOCTYPE','dt','em','fieldset','form','h1','h2','h3','h4',
  'h5','h6','head','html','hr','i','img','input','ins','kbd','label','legend','li','link','map','meta','noscript',
  'object','ol','optgroup','option','p','param','pre','q','samp','script','select','small','span','strong','style',
  'sub','sup','table','tbody','td','textarea','tfoot','th','thead','title','tr','tt','ul','var'
);

$tagsToStrip = array( 'span' );

var_dump( strip_tags( $text, sprintf( '<%s>', implode( '><', array_diff( $validTags, $tagsToStrip ) ) ) ) );

我使用了你自己的列表,但我结合了sprintf(),implode()和array_diff()来完成特定的任务,共同实现目标。

希望它有所帮助。