Comment sélectionner une table contenant certains mots clés - c # - xpath - htmlagilitypack

c# html-agility-pack keyword select xpath

Question

Je dois collecter des informations à partir d'une page de produit sans classe ni identifiant. J'utilise htmlagilitypack et c # 4.0.

Il existe de nombreuses tables dans le code source de cette page de produit. La table de prix contient la chaîne "KDV". Je voudrais donc obtenir cette table "KDV" contenant la chaîne. Comment puis je faire ça ?

Le xpath ci-dessous sélectionnerait toutes les tables par exemple

string srxPathOfCategory = "//table";
var selectedNodes = myDoc.DocumentNode.SelectNodes(srxPathOfCategory);

Le code ci-dessous sélectionne la table mais en partant de la plupart des tables externes. Je dois sélectionner la table la plus interne qui contient cette chaîne donnée

string srxPathOfCategory = "//table";
var selectedNodes = myDoc.DocumentNode.SelectNodes(srxPathOfCategory);

c #, xpath, htmlagilitypack

Réponse acceptée

Le code ci-dessous sélectionne la table mais en partant de la plupart des tables externes. Je dois sélectionner la table la plus interne qui contient cette chaîne donnée

Utiliser :

//table
    [not(descendant::table) 
   and 
     .//text()[contains(., ' KDV')]
    ]

Ceci sélectionne toute table du document XML qui n'a pas de descendant de table et qui a un descendant de nœud de texte contenant la chaîne " KDV" .

En général, l'expression ci-dessus pourrait sélectionner de nombreux éléments de table .

Si vous ne voulez que l'un d'entre eux sélectionné (dites le premier), utilisez cette expression XPath - remarquez les crochets :

//table
    [not(descendant::table) 
   and 
     .//text()[contains(., ' KDV')]
    ]

Rappelez - vous : si vous souhaitez sélectionner le premier élément someName du document, l’utilisation de cet élément (comme dans la réponse acceptée actuellement) est erronée:

//table
    [not(descendant::table) 
   and 
     .//text()[contains(., ' KDV')]
    ]

C'est la deuxième question la plus fréquemment posée dans XPath (après celle sur la sélection d'éléments avec des noms sans préfixe dans un document XML avec un espace de nom par défaut)

L'expression ci-dessus sélectionne en fait n'importe someName élément someName du document, qui est le premier enfant de son parent - essayez-le.

Ce comportement non intuitif s'explique par le fait que l'opérateur XPath [] a une priorité plus élevée (priorité) que le // pseudo-opérateur.

L'expression correcte qui sélectionne réellement uniquement le premier élément someName (dans tout document XML), s'il en existe un, est la suivante:

//table
    [not(descendant::table) 
   and 
     .//text()[contains(., ' KDV')]
    ]

Ici, les crochets sont utilisés pour remplacer explicitement la priorité de l'opérateur XPath par défaut.


Réponse populaire

Il pourrait y avoir un moyen plus efficace de le faire. Quoi qu'il en soit, ceci est le code complet que j'ai utilisé pour votre cas et qui fonctionne pour moi

        HtmlDocument doc = new HtmlDocument();
        string url = "http://www.pratikev.com/fractalv33/pratikEv/pages/viewProduct.jsp?pInstanceId=3138821";
        using (var response = (WebRequest.Create(url).GetResponse()))
        {
            doc.LoadHtml(new StreamReader(response.GetResponseStream()).ReadToEnd());
        }
        /*There is an bug in the xpath used here. Should have been 
          (//table/tr/td/font[contains(.,'KDV')])[1]/ancestor::table[2] 
          See Dimitre's answer for an explanation and an alternative / 
          more generic / (needless to say) better approach */
        string xpath = "//table/tr/td/font[contains(.,'KDV')][1]/ancestor::table[2]"; 
        HtmlNode table = doc.DocumentNode.SelectSingleNode(xpath);



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi