2009-04-27 47 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); 

这允许用一组不同的锚属性调用该函数。