C'est un peu difficile, mais vous pouvez le faire de cette façon:
$html = <<< HTML
<div><p>The CEO of the Dexia bank <em>has</em> just decided to retire.</p></div>
HTML;
J'ai ajouté un élément d'importance juste pour illustrer le fait que cela fonctionne avec les éléments en ligne aussi.
Configuration
$dom = new DOMDocument;
$dom->formatOutput = TRUE;
$dom->loadXML($html);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//text()[contains(., "Dexia")]');
La chose intéressante est au-dessus du XPath bien sûr. Il interroge le DOM chargé pour tous les nœuds DOMText
contenant l'aiguille "Dexia". Le résultat est DOMNodeList
(comme d'habitude).
Le remplacement
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);
Le trouvé $node
contiendra la chaîne Le PDG de la banque Dexia pour wholeText
, bien qu'il soit à l'intérieur de l'élément P
. C'est parce que le $node
a un frère DOMElement
avec l'emphase après banque. Je crée le lien comme une chaîne à la place d'un nœud et remplace toutes les occurrences de "Dexia" (indépendamment de la limite de mot - ce serait un bon appel pour Regex) dans le wholeText
avec lui. Ensuite, je crée un DocumentFragment
à partir de la chaîne résultante et remplace le nœud DOMText
par celui-ci.
W3C vs PHP
L'utilisation DocumentFragement::applyXML()
est une approche non standard, car la méthode ne fait pas partie du W3C DOM Spéc.
Si vous souhaitez effectuer le remplacement avec l'API standard, vous devez d'abord créer l'élément A
en tant que nouveau DOMElement
. Ensuite, vous devrez trouver le décalage de "Dexia" dans le nodeValue
du DOMText
et diviser le nœud DOMText
en deux nœuds à cette position. Supprimez Dexia du frère retourné et insérez l'élément de lien, avant le second. Répétez cette procédure avec le noeud frère jusqu'à ce qu'il n'y ait plus de chaînes Dexia dans le noeud. Voici comment faire pour une occurence de 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);
}
Et enfin la sortie
<div>
<p>The CEO of the <a href="info.php?tag=dexia">Dexia</a> bank <em>has</em> just decided to retire.</p>
</div>
Avez-vous d'utiliser simple_html_dom? Cela semble être quelque chose qui pourrait être accompli avec regex en utilisant preg_replace. –
@threendib HTML n'est pas un format standard. – Gordon