2011-01-11 58 views
2

我期待採取的標記,如:PHP 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這樣的庫似乎太重了,看起來它應該是一個簡單的任務。

回答

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> 
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(),內爆()和和array_diff()做特定任務共同實現目標。

希望它有幫助。