2009-04-27 2 views
5

У меня есть функция, которая заменяет атрибут href якоря в строке, используя DOMDocument от Php. Вот отрывок:Как предотвратить DOMDocument Php от кодирования объектов 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_replace или preg_replace_callback может сделать трюк.
Я не предлагаю возиться о html-документах с регулярным выражением вообще, но для небольшого четко определенного подмножества они подходят.

1

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

Откуда берется текст? Не можете ли вы сделать замену в фактическом html-документе?

+0

loadHTML, нет перевода сущности. Я в конечном итоге взломал проблему непродолжительным образом, запустив mb_substr ($ text, 122, -19); на результат из $ doc-> saveHTML(). Хлоп! :) $ текст - это переведенная строка с метками привязки места, поэтому замена должна выполняться во время выполнения.Я бы предпочел не разобрать весь документ, так как было бы трудно разобрать только переведенные ссылки. Хорошая идея. – thesmart

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. 

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

-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); 

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

Смежные вопросы