2010-09-16 12 views
4

J'essaie d'utiliser SimpleXML en combinaison avec XPath pour trouver des nœuds qui contiennent une certaine chaîne.Utilisez XPath avec PHP SimpleXML pour trouver des nœuds contenant une chaîne

<?php 
$xhtml = <<<EOC 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de"> 
    <head> 
     <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 
     <title>Test</title> 
    </head> 
    <body> 
     <p>Find me!</p> 
     <p> 
      <br /> 
      Find me! 
      <br /> 
     </p> 
    </body> 
</html> 
EOC; 

$xml = simplexml_load_string($xhtml); 
$xml->registerXPathNamespace('xhtml', 'http://www.w3.org/1999/xhtml'); 

$nodes = $xml->xpath("//*[contains(text(), 'Find me')]"); 

echo count($nodes); 

Sortie prévue: 2 sortie réelle: 1

Quand je change l'xhtml du deuxième alinéa à

<p> 
    Find me! 
    <br /> 
</p> 

il fonctionne comme prévu. Comment mon expression XPath doit-elle ressembler à tous les nœuds contenant 'Trouvez-moi', peu importe où ils se trouvent? L'utilisation de DOM-XML de PHP est une option, mais pas souhaitée.

Merci d'avance!

Répondre

9

Cela dépend de ce que vous voulez faire. Vous pouvez sélectionner tous les éléments <p/> contenant « Trouve-moi » dans l'un de leurs descendants avec

//xhtml:p[contains(., 'Find me')] 

Cela renverra les doublons et donc vous ne spécifiez pas le genre de nœuds, puis il retournera ainsi <body/> et <html/> .

Ou peut-être vous voulez un nœud qui a un nœud de texte enfant (pas un descendant) qui contient « Trouvez-moi »

//*[text()[contains(., 'Find me')]] 

Celui-ci ne reviendra pas <html/> ou <body/>.


j'oublié de mentionner que . représente l'ensemble du contenu textuel d'un nœud. text() est utilisé pour récupérer [un jeu de nœuds] de nœuds de texte. Le problème avec votre expression contains(text(), 'Find me') est que ne fonctionne que sur les chaînes, pas les nœuds, et par conséquent, il convertit text() à la valeur du premier nœud, ce qui explique pourquoi la suppression du premier <br/> le fait fonctionner.

+0

Merci, ça marche! – xlttj

0
$doc = new DOMDocument(); 
    $doc->loadHTML($xhtml); 

    $xPath = new DOMXpath($doc); 
    $xPathQuery = "//text()[contains(translate(.,'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'Find me')]"; 
    $elements = $xPath->query($xPathQuery); 

    if($elements->length > 0){ 

    foreach($elements as $element){ 
     print "Found: " .$element->nodeValue."<br />"; 
    }} 
+1

Cela ne fonctionne pas –

1

Err, euh? Mais merci @Jordy pour la réponse rapide. D'abord, c'est DOM-XML, ce qui n'est pas souhaitable, puisque tout le reste de mon script est fait avec SimpleXML. Deuxièmement, pourquoi traduisez-vous en majuscules et recherchez une chaîne inchangée 'Trouvez-moi'? «La recherche de« TROUVEZ-MOI »donnerait un résultat.

Mais vous me pointé vers la bonne direction:

$nodes = $xml->xpath("//text()[contains(., 'Find me')]"); 

le tour est joué!

+0

Ensuite, votez ma réponse comme réponse: D La traduction en majuscule est quand vous voulez la rendre non sensible à la casse – Jordy

1

Je cherchais un moyen de trouver si un nœud avec la valeur exacte "Trouvez-moi" existe et cela a semblé fonctionner.

$node = $xml->xpath("//text()[.='Find Me']");