2012-05-14 4 views
15

Warum wählt dies alle meine <li> Elemente in meinem Dokument?Html Agility Pack, SelectNodes von einem Knoten

HtmlWeb web = new HtmlWeb(); 
HtmlDocument doc = web.Load(url); 

var travelList = new List<Page>(); 
var liOfTravels = doc.DocumentNode.SelectSingleNode("//div[@id='myTrips']") 
        .SelectNodes("//li"); 

Was ich will, ist, alle <li> Elemente im <div> mit einem id von „myTrips“ zu bekommen.

Antwort

15

Es ist ein wenig verwirrend, weil Sie erwarten, dass es ein selectNodes nur für das div mit der ID "myTrips" ausführen würde. Wenn Sie jedoch ein anderes SelectNodes ("// li") ausführen, wird eine weitere Suche von oben ausgeführt des Dokuments.

Ich reparierte das, indem ich die Aussage in eine kombinierte, aber das würde nur auf einer Webseite funktionieren, wo Sie nur ein Div mit einer ID "mytrips" haben. Die Abfrage würde folgendermaßen aussehen:

doc.DocumentNode.SelectNodes ("// div [@ id = 'myTrips'] // li");

4

Sie können dies tun Abfrage mit einer Linq:

HtmlWeb web = new HtmlWeb(); 
HtmlDocument doc = web.Load(url); 

var travelList = new List<HtmlNode>(); 
foreach (var matchingDiv in doc.DocumentNode.DescendantNodes().Where(n=>n.Name == "div" && n.Id == "myTrips")) 
{ 
    travelList.AddRange(matchingDiv.DescendantNodes().Where(n=> n.Name == "li")); 
} 

Ich hoffe, es

1

Dies scheint als gut zu mir unlogisch hilft, wenn Sie eine Select Methode auf einem bestimmten Knoten ausgeführt Ich dachte, es würde nur nach Dingen unter diesem Knoten suchen, nicht im Dokument im Allgemeinen.

Trotzdem OP, wenn Sie diese Zeile ändern: var liOfTravels = doc.DocumentNode.SelectSingleNode ("// div [@ id = 'myTrips'" ")". SelectNodes ("// li");

TO: var liOfTravels = doc.DocumentNode.SelectSingleNode ("// div [@ id = 'myTrips']"). SelectNodes ("li");

Ich denke, Sie werden in Ordnung sein, ich hatte gerade das gleiche Problem und das reparierte es für mich. Ich bin mir aber nicht sicher, ob das li ein direktes Kind des Knotens sein müsste, den Sie haben.

12
var liOfTravels = doc.DocumentNode.SelectSingleNode("//div[@id='myTrips']") 
       .SelectNodes(".//li"); 

Beachten Sie den Punkt in der zweiten Zeile. Grundsätzlich in dieser Hinsicht HTMLAgitilityPack vollständig auf XPath-Syntax basiert, aber das Ergebnis ist nicht intuitiv, da diese Abfragen effektiv gleich sind:

doc.DocumentNode.SelectNodes("//li"); 
some_deeper_node.SelectNodes("//li"); 
+0

Ich glaube nicht, dass die Abfragen die gleichen sind. Wenn er das erste Mal auswählt, "// div [@ id = 'myTrips']" ändert sich der aktuelle Knoten. Deshalb sollte die zweite Auswahl "./li" (irgendwo vom aktuellen Knoten) und nicht "// li" (irgendwo von root) sein. Agilität macht genau das, was erwartet wird. – derloopkat

+0

@derloopkat, sie ** sind ** die gleichen (es gibt keine IMHO hier; wenn sie nicht wären, könnten Sie den Punkt in der Lösungsabfrage fallen lassen, aber Sie können nicht, können Sie?). Leider sucht HTMLAgilityPack von der Wurzel aus, egal auf welchem ​​Knoten Sie sich befinden. Der IMHO-Teil ist dies - normalerweise ist der Punkt, an dem man sich auf einen bestimmten Knoten konzentriert, der, dass man die Suche ** von ** diesem Knoten aus fortsetzt und nicht wieder von der Wurzel. Die Lösungsabfrage ohne hinzugefügten Punkt in der zweiten Unterabfrage würde überhaupt keinen Sinn ergeben, also warum sie unterstützen? – greenoldman

+0

Wir sprechen über verschiedene Dinge. Als ich sagte, dass die Fragen nicht die gleichen sind, sprach ich von "// li" und ".//li". Mit "diese Abfragen" verweisen Sie auf die folgenden Abfragen. – derloopkat

5

einen neuen Knoten erstellen kann in einigen Situationen von Vorteil sein und können verwendet werden, um die XPaths intuitiver. Ich habe das an einigen Orten nützlich gefunden.

var myTripsDiv = doc.DocumentNode.SelectSingleNode("//div[@id='myTrips']"); 
var myTripsNode = HtmlNode.CreateNode(myTripsDiv.InnerHtml); 
var liOfTravels = myTripsNode.SelectNodes("//li"); 
Verwandte Themen