2010-11-04 4 views
0

J'utilise PHP pour récupérer le contenu pour une URL donnée et XPATH. J'utilise DOMDocument/DOMXPath (avec requête ou évaluation).trop long xpath avec DOMXpath requête/évaluer ne rien retourner

Pour un petit xpath, j'obtiens un résultat correct, mais pour un xpath plus long, cela ne fonctionne pas. (Et ce XPath semble être bon (je les ai obtenus avec Xpather (plugin firefox) et les RETESTÉ avec YQL)

Avez-vous des conseils sur cette curieuse difficulté

Exemple de code:.?

$doc = new DOMDocument(); 
$myXMLString = file_get_contents('http://stackoverflow.com/questions/4097230/too-long-xpath-with-domxpath-query-evaluate-return-nothing'); 
@$doc->loadHTML($myXMLString); //@ to suppress warnings 
           //(good for not ending markup) 
$xpath = new DOMXPath($doc); 

$fullPath ="/html/body/small/path"; //it works 
//$fullPath = "/html/body/full/path/with/lot/of/markup";//does not works 
$entries = $xpath->query($fullPath); 
//or ->evalutate($fullPath) (same behaviour) 
//$entries return DOMNodeList (empty for a long path query, 
//        correct for a small path query) 

je test avec restriction d'attribut, mais il est semble ne pas changer (avec petit XPath cela fonctionne, avec plus il ne fonctionne plus)

Exemple: pour cette page courante:

$fullPath = "/html 
       /body 
       /div[4] 
       /div[@id='content'] 
       /div[@id='question-header'] 
        /h1 
        /a";//works (retrieve the question title) 
$fullPath = "/html 
       /body 
       /div[4] 
       /div[@id='content'] 
       /div[@id='mainbar'] 
        /div[@id='question'] 
        /table 
        /tbody 
        /tr[2] 
         /td[2] 
         /div[@id='comments-4097230'] 
         /table 
         /tbody 
          /tr[@id='comment-4408626'] 
          /td[2] 
          /div 
          /a"; //does'nt work 
            //(should retrieve 'gaby' from comment) 

Edit:

-je tester avec SimpleXML lib, et j'ai exactement le même comportement (bon résultat pour les petites requête, rien pour une longue requête).


Edit 2:

je coupe aussi la plus longue XPath en supprimant certains premier élément et cela fonctionne. BTW Je ne comprends vraiment pas pourquoi un chemin xpath correct ne fonctionne pas.

+1

donnez-nous le xml et xpath –

+1

J'ajoute un exemple. – AlphaB

Répondre

3

Nous allons passer par cette étape par étape:

Étape 1: répliquant l'erreur.

Après avoir vérifié que le XPath sera en effet pas retourner un résultat, je l'ai écrit un petit script pour voir la profondeur de la XPath ira avant qu'il ne casse

foreach (explode('/', $fullPath) as $segment) { 
    $xpath .= trim($segment); 
    echo '-------------------------------------------', PHP_EOL, 
     'Trying: ', $xpath, PHP_EOL, 
     '-------------------------------------------', PHP_EOL; 
    echo $xp->evaluate("string($xpath)"), PHP_EOL; 
    $xpath .= '/'; 
} 

La dernière chose qu'il retournera un résultat pour est

/html/body/div[4]/div[@id='content']/div[@id='mainbar']/div[@id='question']/table 

Étape 2: vérifier le balisage

Alors j'ai vérifié le balisage retourné par DOMDocument::saveHTML() pour voir à quoi il ressemble et il n'y avait pas <tbody>(reformaté pour une meilleure lisibilité):

<div id="question"> 
    <div class="everyonelovesstackoverflow" id="adzerk1"></div> 
     <table> 
      <tr><td class="votecell"> 

Je puis vérifié cette très page pour voir si elle était lancer DOM loin ou si ça n'existe vraiment pas. Ce n'était pas là.Apparemment, Firebug il insère, ce qui expliquerait pourquoi vous avez obtenu le résultat avec XPather (mais pas pourquoi vous avez obtenu avec YQL):

Screenshot showing page source and apparently bugged Firebug view

Étape 3: proofchecking et conclusion

j'ai enlevé le <tbody> à partir du XPath et relancer le script. Pas de problème. Renvoie "Gaby".

Alors que je soupçonnais un bug dans Firebug en premier, Alejandro a commenté que cela se produirait aussi dans les DeveloperTools d'IE. J'ai alors suspecté que cela soit ajouté par JavaScript mais je n'ai pas pu le vérifier. Après d'autres recherches, Alejandro m'a indiqué Why does firebug add <tbody> to <table>? - il ne s'agit pas de Firebug ni de JavaScript, mais du navigateur lui-même.

Donc, pour modifier ma conclusion:

balisage Dont la confiance que vous voyez rendiez dans le navigateur, car il peut être modifié par le navigateur ou d'autres technologies. DOM ne téléchargera que ce qui est servi directement. Si vous rencontrez à nouveau des problèmes similaires, vous savez maintenant comment l'aborder.


Certains sidenotes supplémentaires

Sauf si vous devez modifier le balisage avant de le nourrir à DOM, vous ne devez pas utiliser file_get_contents() pour charger le contenu. Vous pouvez utiliser DOM de loadHTMLFile():

$dom->loadHTMLFile('http://www.example.com/foo.htm'); 

En outre, la bonne façon de supprimer les erreurs est de dire libxml à utiliser est gestionnaire d'erreur interne. Mais au lieu de gérer les erreurs, vous les effacez simplement. Cela n'affectera que les erreurs relatives à libxml, par ex. erreurs d'analyse (par opposition à toutes les erreurs PHP):

libxml_use_internal_errors(TRUE); 
libxml_clear_errors(); 

Enfin, les requêtes XPath peuvent se faire par rapport à un nœud de contexte. Donc, alors que le XPath long est efficace en termes de temps de recherche, vous pouvez simplement utiliser getElementById() pour obtenir le nœud le plus profond connu et ensuite utiliser un XPath.

En d'autres termes:

libxml_use_internal_errors(TRUE); 
$dom = new DOMDocument; 
$dom->loadHTMLFile('http://www.example.com/foo.htm'); 
libxml_clear_errors(); 
echo $xp->evaluate(
    'string(td[2]/div/a)', 
    $dom->getElementById('comment-4408626')); 

retournera "Gaby" aussi bien.

+1

Désolé, mon message n'était pas assez précis. Je compte retourner un DOMNodeList avec un noeud (qui contient gaby). (et merci pour des conseils à propos de libxml) – AlphaB

+0

J'ai vu la classe yql mais je préfère une méthode rapide et plus petite si possible (utilisation DOM moyenne ou simple xml lib mais pas de service externe) – AlphaB

+0

@AurelienB puisque votre autre question suggère que vous utilisez Zend Studio , s'il vous plaît essayez ce qui suit: télécharger le balisage et enregistrez-le dans un fichier. Ouvrez le fichier avec la perspective XML dans Zend Studio. Si ce n'est pas valide, vous devrez peut-être le corriger en premier. Utilisez ensuite l'évaluateur XPath en bas à gauche pour tester s'il détecte vos noeuds. – Gordon