Как я могу предотвратить DOMDocument Php от кодирования HTML объектов? - PullRequest
5 голосов
/ 27 апреля 2009

У меня есть функция, которая заменяет атрибут href якорей в строке, используя DOMDocument от Php. Вот фрагмент кода:

$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) окружает $ text тегами doctype, html, body и т. Д. Я пытался обойти это, делая это вместо loadHTML ():

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

К сожалению, это кодирует все объекты (включая якоря). Кто-нибудь знает как это отключить? Я уже тщательно просмотрел документы и попытался взломать их, но не могу понять.

Спасибо! :)

Ответы [ 4 ]

3 голосов
/ 27 апреля 2009
$ text - переведенная строка с тегами-метками-заполнителями

Если эти заполнители имеют строгий, четко определенный формат, простой preg_replace или preg_replace_callback может помочь.
Я не предлагаю возиться с HTML-документами с регулярными выражениями в целом, но для небольшого четко определенного подмножества они подходят.

1 голос
/ 27 апреля 2009

XML имеет только очень мало предопределенных сущностей . Все ваши html-объекты определены где-то еще. Когда вы используете loadhtml (), эти определения сущностей загружаются автоматически, с помощью loadxml () (или вообще без load ()) это не так.
createTextNode () делает именно то, что предлагает имя. Все, что вы передаете как значение, рассматривается как текстовое содержимое, а не как разметка. То есть если вы передаете в разметку что-то, имеющее особое значение (<,>, ...), это кодируется таким образом, чтобы синтаксический анализатор мог отличить текст от фактической разметки (& lt ;, & gt ;, ...)

Откуда берется $ text? Вы не можете сделать замену в реальном HTML-документе?

0 голосов
/ 28 апреля 2009

ОК, вот окончательное решение, которое я выбрал. Решили согласиться с предложением 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);

Это позволяет вызывать функцию с набором различных атрибутов привязки.

0 голосов
/ 27 апреля 2009

Я закончила хакерским взломом, изменив:

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.

Может кто-нибудь придумать что-нибудь получше?

...