8

我有一个使用 PHP 的 DOMDocument 替换字符串中锚点的 href 属性的函数。这是一个片段:

$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($text) 在 doctype、html、body 等标签中包围了 $text。我尝试通过这样做而不是 loadHTML() 来解决这个问题:

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

不幸的是,这对所有实体(包括锚)进行了编码。有谁知道如何关闭这个?我已经彻底查看了文档并尝试破解它,但无法弄清楚。

谢谢!:)

4

4 回答 4

4
$text 是带有占位符锚标记的翻译字符串

如果这些占位符具有严格的、明确定义的格式,则简单的preg_replacepreg_replace_callback可能会解决问题。
我一般不建议用正则表达式摆弄 html 文档,但对于一个定义明确的小子集,它们是合适的。

于 2009-04-27T19:18:16.430 回答
1

XML 只有很少的预定义实体。您所有的 html 实体都在其他地方定义。当您使用 loadhtml() 时,这些实体定义会自动加载,而使用 loadxml()(或根本没有 load())则不会。
createTextNode() 完全符合其名称的含义。您作为值传递的所有内容都被视为文本内容,而不是标记。即,如果您将具有特殊含义的内容传递给标记(<、>、...),它的编码方式是解析器可以将文本与实际标记(<、>、...)区分开来

$text 是从哪里来的?您不能在实际的 html 文档中进行替换吗?

于 2009-04-27T09:35:52.587 回答
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> 

进入这个:

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

任何人都可以找出更好的东西吗?

于 2009-04-27T17:54:43.183 回答
-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);

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

于 2009-04-27T21:52:43.393 回答