2010-06-30 4 views
6

J'essaie d'utiliser la classe php simple_html_dom pour créer une fonction de recherche et de remplacement qui recherche des mots-clés et les remplace par un lien vers une définition du mot-clé , avec le mot-clé comme texte de lien.trouver et remplacer des mots-clés par des liens hypertexte dans un fragment html, via php dom

Comment puis-je trouver et remplacer "Dexia" par <a href="info.php?tag=dexia">Dexia</a> en utilisant cette classe, à l'intérieur d'une chaîne telle que <div><p>The CEO of the Dexia bank has just decided to retire.</p></div>?

+0

Avez-vous d'utiliser simple_html_dom? Cela semble être quelque chose qui pourrait être accompli avec regex en utilisant preg_replace. –

+0

@threendib HTML n'est pas un format standard. – Gordon

Répondre

5

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> 
+0

@gordon: c'est très intéressant. J'ai simplifié ma question car je m'attendais à quelque chose de plus simple; en réalité, j'ai environ 500 mots-clés. Cette approche évolue-t-elle correctement? Je devrais avoir une double boucle foreach je suppose. – pixeline

+0

@pixeline bien, c'est difficile au début mais seulement parce que DOM est assez verbeux et que vous devez penser en nœuds au lieu de texte. Je comprends pourquoi les gens veulent le faire avec Regex, mais ce n'est vraiment pas si difficile une fois que vous y êtes arrivé. Je veux dire, c'est juste 15 lignes de code. Mettez-le dans une classe de service appropriée et vous avez un outil réutilisable cool. Je ne sais pas comment cela fonctionne, donc vous devrez l'évaluer vous-même et voir si c'est acceptable pour vous. – Gordon

+1

Cela fonctionne plutôt bien (j'ai dû changer pour loadHTML car le html que je passe vient d'un CMS et pourrait ne pas être bien formé.) – pixeline