Это несколько сложно, но вы могли бы сделать это следующим образом:
$html = <<< HTML
<div><p>The CEO of the Dexia bank <em>has</em> just decided to retire.</p></div>
HTML;
Я добавил элемент выделения только для иллюстрации того, что он работает и со встроенными элементами.
Настройка
$dom = new DOMDocument;
$dom->formatOutput = TRUE;
$dom->loadXML($html);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//text()[contains(., "Dexia")]');
Интересная вещь выше - это, конечно, XPath.Он запрашивает загруженный DOM для всех DOMText
узлов, содержащих иглу "Dexia".Результат - DOMNodeList
(как обычно).
Замена
foreach($nodes as $node) {
$link = '<a href="info.php?tag=dexia">Dexia</a>';
$replaced = str_replace('Dexia', $link, $node->wholeText);
$newNode = $dom->createDocumentFragment();
$newNode->appendXML($replaced);
$node->parentNode->replaceChild($newNode, $node);
}
echo $dom->saveXML($dom->documentElement);
Найденный $node
будет содержать строку Генеральный директорБанк Дексиа для wholeText
, несмотря на то, что он находится внутри элемента P
.Это потому, что у $node
есть родной брат DOMElement
с акцентом после банка .Я создаю ссылку как строку вместо узла и заменяю все вхождения Dexia (независимо от границы слова - это было бы хорошим вызовом для Regex) в wholeText
с ним.Затем я создаю DocumentFragment
из полученной строки и заменяю ее узлом DOMText
.
W3C против PHP
Использование DocumentFragement::applyXML()
является нестандартным подходом, поскольку этот метод не является частью спецификаций DOM W3C.
Если вы хотите выполнить замену стандартным API, вам сначала нужно создать элемент A
как новый DOMElement
.Тогда вам нужно найти смещение «Dexia» в nodeValue
DOMText
и разделить узел DOMText
на два узла в этой позиции.Удалите Dexia из возвращенного брата и вставьте элемент Link перед вторым.Повторите эту процедуру с одноуровневым узлом, пока в узле не будет найдено больше строк Dexia.Вот как это сделать для одного случая Дексии:
foreach($nodes as $node) {
$link = $dom->createElement('a', 'Dexia');
$link->setAttribute('href', 'info.php?tag=dexia');
$offset = strpos($node->nodeValue, 'Dexia');
$newNode = $node->splitText($offset);
$newNode->deleteData(0, strlen('Dexia'));
$node->parentNode->insertBefore($link, $newNode);
}
И, наконец, вывод
<div>
<p>The CEO of the <a href="info.php?tag=dexia">Dexia</a> bank <em>has</em> just decided to retire.</p>
</div>