2009-04-27 49 views
5

我有一個函數,使用Php的DOMDocument替換字符串中錨點的href屬性。這裏有一個片段:如何防止Php的DOMDocument對html實體進行編碼?

$doc  = new DOMDocument('1.0', 'UTF-8'); 
$doc->loadHTML($text); 
$anchors = $doc->getElementsByTagName('a'); 

foreach($anchors as $a) { 
    $a->setAttribute('href', 'http://google.com'); 
} 

return $doc->saveHTML(); 

的問題是,loadHTML($文本)環繞在DOCTYPE HTML,身體等標籤$文本。我試圖通過這樣做而不是loadHTML():

$doc  = new DOMDocument('1.0', 'UTF-8'); 
$node  = $doc->createTextNode($text); 
$doc->appendChild($node); 
... 

不幸的是,這編碼所有的實體(包括錨點)。有誰知道如何關閉此功能?我已經徹底查看了文檔並試圖對其進行黑客入侵,但無法弄清楚。

謝謝! :)

回答

3
$文字是翻譯的字符串佔位錨標記

如果這些佔位符有嚴格,明確定義的格式簡單preg_replacepreg_replace_callback可能做的伎倆。
我不建議用一般的正則表達式來處理html文檔,但對於一個明確定義的小的子集來說,它們是合適的。

1

XML只有very few predefined entities。你所有的html實體都是在別的地方定義的。當你使用loadhtml()時,這些實體定義是自動加載的,而loadxml()(或者根本不加載())它們不是。
createTextNode()完全正是名字所暗示的。您傳遞的所有值都被視爲文本內容,而不是標記。即如果將具有特殊含義的內容傳遞給標記(<,>,...),則它將以某種方式編碼,解析器可以將文本與實際標記區分開來(& lt,& gt ;, ...)

$ text從哪裏來?你不能在實際的html文件中做替換嗎?

+0

loadHTML,不會發生實體轉換。我最終通過運行mb_substr($ text,122,-19)以脆弱的方式解決了這個問題。從$ doc-> saveHTML()的結果。哎呀! :) $ text是一個帶有佔位符錨標記的翻譯字符串,因此替換必須在運行時完成。我寧願不分析整個文檔,因爲只解析翻譯後的鏈接會很困難。 雖然好主意。 – thesmart 2009-04-27 17:50:42

0

我結束了在一個微妙的方式入侵這一點,改變:

return $doc->saveHTML(); 

到:

$text  = $doc->saveHTML(); 
return mb_substr($text, 122, -19); 

這削減了所有不必要的垃圾,改變這樣的:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" 
"http://www.w3.org/TR/REC-html40/loose.dtd"> <html><body><p> 
You can <a href="http://www.google.com">click here</a> to visit Google.</p> 
</body></html> 

into into:

You can <a href="http://www.google.com">click here</a> to visit Google. 

任何人都可以找出更好的東西嗎?

-1

好的,這是我最終的解決方案。決定採用VolkerK的建議。

public static function ReplaceAnchors($text, array $attributeSets) 
{ 
    $expression = '/(<a)([\s\w\d:\/=_&\[\]\+%".?])*(>)/'; 

    if (empty($attributeSets) || !is_array($attributeSets)) { 
     // no attributes to set. Set href="#". 
     return preg_replace($expression, '$1 href="#"$3', $text); 
    } 

    $attributeStrs = array(); 
    foreach ($attributeSets as $attributeKeyVal) { 
     // loop thru attributes and set the anchor 
     $attributePairs = array(); 
     foreach ($attributeKeyVal as $name => $value) { 
      if (!is_string($value) && !is_int($value)) { 
       continue; // skip 
      } 

      $name    = htmlspecialchars($name); 
      $value    = htmlspecialchars($value); 
      $attributePairs[] = "$name=\"$value\""; 
     } 
     $attributeStrs[] = implode(' ', $attributePairs); 
    } 

    $i  = -1; 
    $pieces = preg_split($expression, $text); 
    foreach ($pieces as &$piece) { 
     if ($i === -1) { 
      // skip the first token 
      ++$i; 
      continue; 
     } 

     // figure out which attribute string to use 
     if (isset($attributeStrs[$i])) { 
      // pick the parallel attribute string 
      $attributeStr = $attributeStrs[$i]; 
     } else { 
      // pick the last attribute string if we don't have enough 
      $attributeStr = $attributeStrs[count($attributeStrs) - 1]; 
     } 

     // build a opening new anchor for this token. 
     $piece = '<a '.$attributeStr.'>'.preg_replace($expression, '$1 href="#"$3', $piece); 
     ++$i; 
    } 

    return implode('', $pieces); 

這允許用一組不同的錨屬性調用該函數。